diff --git a/.stats.yml b/.stats.yml index 089abe5d8..5a1f2ff0e 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 95 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-0ee6b36cf3cc278cef4199a6aec5f7d530a6c1f17a74830037e96d50ca1edc50.yml -openapi_spec_hash: e8ec5f46bc0655b34f292422d58a60f6 -config_hash: d9b6b6e6bc85744663e300eebc482067 +configured_endpoints: 99 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-794a6ed3c3d3d77887564755168056af8a426b17cf1ec721e3a300503dc22a41.yml +openapi_spec_hash: 25a81c220713cd5b0bafc221d1dfa79a +config_hash: 0b768ed1b56c6d82816f0fa40dc4aaf5 diff --git a/README.md b/README.md index 6a05116a5..dece1cd29 100644 --- a/README.md +++ b/README.md @@ -286,7 +286,7 @@ OpenAIClient client = OpenAIOkHttpClient.builder() The SDK provides conveniences for streamed chat completions. A [`ChatCompletionAccumulator`](openai-java-core/src/main/kotlin/com/openai/helpers/ChatCompletionAccumulator.kt) -can record the stream of chat completion chunks in the response as they are processed and accumulate +can record the stream of chat completion chunks in the response as they are processed and accumulate a [`ChatCompletion`](openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletion.kt) object similar to that which would have been returned by the non-streaming API. @@ -334,6 +334,205 @@ client.chat() ChatCompletion chatCompletion = chatCompletionAccumulator.chatCompletion(); ``` +## Structured outputs with JSON schemas + +Open AI [Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs?api-mode=chat) +is a feature that ensures that the model will always generate responses that adhere to a supplied +[JSON schema](https://json-schema.org/overview/what-is-jsonschema). + +A JSON schema can be defined by creating a +[`ResponseFormatJsonSchema`](openai-java-core/src/main/kotlin/com/openai/models/ResponseFormatJsonSchema.kt) +and setting it on the input parameters. However, for greater convenience, a JSON schema can instead +be derived automatically from the structure of an arbitrary Java class. The JSON content from the +response will then be converted automatically to an instance of that Java class. A full, working +example of the use of Structured Outputs with arbitrary Java classes can be seen in +[`StructuredOutputsExample`](openai-java-example/src/main/java/com/openai/example/StructuredOutputsExample.java). + +Java classes can contain fields declared to be instances of other classes and can use collections: + +```java +class Person { + public String name; + public int birthYear; +} + +class Book { + public String title; + public Person author; + public int publicationYear; +} + +class BookList { + public List books; +} +``` + +Pass the top-level class—`BookList` in this example—to `responseFormat(Class)` when building the +parameters and then access an instance of `BookList` from the generated message content in the +response: + +```java +import com.openai.models.ChatModel; +import com.openai.models.chat.completions.ChatCompletionCreateParams; +import com.openai.models.chat.completions.StructuredChatCompletionCreateParams; + +StructuredChatCompletionCreateParams params = ChatCompletionCreateParams.builder() + .addUserMessage("List some famous late twentieth century novels.") + .model(ChatModel.GPT_4_1) + .responseFormat(BookList.class) + .build(); + +client.chat().completions().create(params).choices().stream() + .flatMap(choice -> choice.message().content().stream()) + .flatMap(bookList -> bookList.books.stream()) + .forEach(book -> System.out.println(book.title + " by " + book.author.name)); +``` + +You can start building the parameters with an instance of +[`ChatCompletionCreateParams.Builder`](openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt) +or +[`StructuredChatCompletionCreateParams.Builder`](openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParams.kt). +If you start with the former (which allows for more compact code) the builder type will change to +the latter when `ChatCompletionCreateParams.Builder.responseFormat(Class)` is called. + +If a field in a class is optional and does not require a defined value, you can represent this using +the [`java.util.Optional`](https://docs.oracle.com/javase/8/docs/api/java/util/Optional.html) class. +It is up to the AI model to decide whether to provide a value for that field or leave it empty. + +```java +import java.util.Optional; + +class Book { + public String title; + public Person author; + public int publicationYear; + public Optional isbn; +} +``` + +Generic type information for fields is retained in the class's metadata, but _generic type erasure_ +applies in other scopes. While, for example, a JSON schema defining an array of books can be derived +from the `BookList.books` field with type `List`, a valid JSON schema cannot be derived from a +local variable of that same type, so the following will _not_ work: + +```java +List books = new ArrayList<>(); + +StructuredChatCompletionCreateParams> params = ChatCompletionCreateParams.builder() + .responseFormat(books.getClass()) + // ... + .build(); +``` + +If an error occurs while converting a JSON response to an instance of a Java class, the error +message will include the JSON response to assist in diagnosis. For instance, if the response is +truncated, the JSON data will be incomplete and cannot be converted to a class instance. If your +JSON response may contain sensitive information, avoid logging it directly, or ensure that you +redact any sensitive details from the error message. + +### Local JSON schema validation + +Structured Outputs supports a +[subset](https://platform.openai.com/docs/guides/structured-outputs#supported-schemas) of the JSON +Schema language. Schemas are generated automatically from classes to align with this subset. +However, due to the inherent structure of the classes, the generated schema may still violate +certain OpenAI schema restrictions, such as exceeding the maximum nesting depth or utilizing +unsupported data types. + +To facilitate compliance, the method `responseFormat(Class)` performs a validation check on the +schema derived from the specified class. This validation ensures that all restrictions are adhered +to. If any issues are detected, an exception will be thrown, providing a detailed message outlining +the reasons for the validation failure. + +- **Local Validation**: The validation process occurs locally, meaning no requests are sent to the +remote AI model. If the schema passes local validation, it is likely to pass remote validation as +well. +- **Remote Validation**: The remote AI model will conduct its own validation upon receiving the JSON +schema in the request. +- **Version Compatibility**: There may be instances where local validation fails while remote +validation succeeds. This can occur if the SDK version is outdated compared to the restrictions +enforced by the remote AI model. +- **Disabling Local Validation**: If you encounter compatibility issues and wish to bypass local +validation, you can disable it by passing +[`JsonSchemaLocalValidation.NO`](openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaLocalValidation.kt) +to the `responseFormat(Class, JsonSchemaLocalValidation)` method when building the parameters. +(The default value for this parameter is `JsonSchemaLocalValidation.YES`.) + +```java +import com.openai.core.JsonSchemaLocalValidation; +import com.openai.models.ChatModel; +import com.openai.models.chat.completions.ChatCompletionCreateParams; +import com.openai.models.chat.completions.StructuredChatCompletionCreateParams; + +StructuredChatCompletionCreateParams params = ChatCompletionCreateParams.builder() + .addUserMessage("List some famous late twentieth century novels.") + .model(ChatModel.GPT_4_1) + .responseFormat(BookList.class, JsonSchemaLocalValidation.NO) + .build(); +``` + +By following these guidelines, you can ensure that your structured outputs conform to the necessary +schema requirements and minimize the risk of remote validation errors. + +### Usage with the Responses API + +_Structured Outputs_ are also supported for the Responses API. The usage is the same as described +except where the Responses API differs slightly from the Chat Completions API. Pass the top-level +class to `text(Class)` when building the parameters and then access an instance of the class from +the generated message content in the response. + +You can start building the parameters with an instance of +[`ResponseCreateParams.Builder`](openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt) +or +[`StructuredResponseCreateParams.Builder`](openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseCreateParams.kt). +If you start with the former (which allows for more compact code) the builder type will change to +the latter when `ResponseCreateParams.Builder.text(Class)` is called. + +For a full example of the usage of _Structured Outputs_ with the Responses API, see +[`ResponsesStructuredOutputsExample`](openai-java-example/src/main/java/com/openai/example/ResponsesStructuredOutputsExample.java). + +### Annotating classes and JSON schemas + +You can use annotations to add further information to the JSON schema derived from your Java +classes, or to exclude individual fields from the schema. Details from annotations captured in the +JSON schema may be used by the AI model to improve its response. The SDK supports the use of +[Jackson Databind](https://github.com/FasterXML/jackson-databind) annotations. + +```java +import com.fasterxml.jackson.annotation.JsonClassDescription; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; + +class Person { + @JsonPropertyDescription("The first name and surname of the person") + public String name; + public int birthYear; + @JsonPropertyDescription("The year the person died, or 'present' if the person is living.") + public String deathYear; +} + +@JsonClassDescription("The details of one published book") +class Book { + public String title; + public Person author; + @JsonPropertyDescription("The year in which the book was first published.") + public int publicationYear; + @JsonIgnore public String genre; +} + +class BookList { + public List books; +} +``` + +- Use `@JsonClassDescription` to add a detailed description to a class. +- Use `@JsonPropertyDescription` to add a detailed description to a field of a class. +- Use `@JsonIgnore` to omit a field of a class from the generated JSON schema. + +If you use `@JsonProperty(required = false)`, the `false` value will be ignored. OpenAI JSON schemas +must mark all properties as _required_, so the schema generated from your Java classes will respect +that restriction and ignore any annotation that would violate it. + ## File uploads The SDK defines methods that accept files. @@ -412,10 +611,7 @@ These methods return [`HttpResponse`](openai-java-core/src/main/kotlin/com/opena import com.openai.core.http.HttpResponse; import com.openai.models.files.FileContentParams; -FileContentParams params = FileContentParams.builder() - .fileId("file_id") - .build(); -HttpResponse response = client.files().content(params); +HttpResponse response = client.files().content("file_id"); ``` To save the response content to a file, use the [`Files.copy(...)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#copy-java.io.InputStream-java.nio.file.Path-java.nio.file.CopyOption...-) method: @@ -528,53 +724,101 @@ The SDK throws custom unchecked exception types: ## Pagination -For methods that return a paginated list of results, this library provides convenient ways access the results either one page at a time, or item-by-item across all pages. +The SDK defines methods that return a paginated lists of results. It provides convenient ways to access the results either one page at a time or item-by-item across all pages. ### Auto-pagination -To iterate through all results across all pages, you can use `autoPager`, which automatically handles fetching more pages for you: +To iterate through all results across all pages, use the `autoPager()` method, which automatically fetches more pages as needed. -### Synchronous +When using the synchronous client, the method returns an [`Iterable`](https://docs.oracle.com/javase/8/docs/api/java/lang/Iterable.html) ```java import com.openai.models.finetuning.jobs.FineTuningJob; import com.openai.models.finetuning.jobs.JobListPage; -// As an Iterable: -JobListPage page = client.fineTuning().jobs().list(params); +JobListPage page = client.fineTuning().jobs().list(); + +// Process as an Iterable for (FineTuningJob job : page.autoPager()) { System.out.println(job); -}; +} -// As a Stream: -client.fineTuning().jobs().list(params).autoPager().stream() +// Process as a Stream +page.autoPager() + .stream() .limit(50) .forEach(job -> System.out.println(job)); ``` -### Asynchronous +When using the asynchronous client, the method returns an [`AsyncStreamResponse`](openai-java-core/src/main/kotlin/com/openai/core/http/AsyncStreamResponse.kt): ```java -// Using forEach, which returns CompletableFuture: -asyncClient.fineTuning().jobs().list(params).autoPager() - .forEach(job -> System.out.println(job), executor); +import com.openai.core.http.AsyncStreamResponse; +import com.openai.models.finetuning.jobs.FineTuningJob; +import com.openai.models.finetuning.jobs.JobListPageAsync; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; + +CompletableFuture pageFuture = client.async().fineTuning().jobs().list(); + +pageFuture.thenRun(page -> page.autoPager().subscribe(job -> { + System.out.println(job); +})); + +// If you need to handle errors or completion of the stream +pageFuture.thenRun(page -> page.autoPager().subscribe(new AsyncStreamResponse.Handler<>() { + @Override + public void onNext(FineTuningJob job) { + System.out.println(job); + } + + @Override + public void onComplete(Optional error) { + if (error.isPresent()) { + System.out.println("Something went wrong!"); + throw new RuntimeException(error.get()); + } else { + System.out.println("No more!"); + } + } +})); + +// Or use futures +pageFuture.thenRun(page -> page.autoPager() + .subscribe(job -> { + System.out.println(job); + }) + .onCompleteFuture() + .whenComplete((unused, error) -> { + if (error != null) { + System.out.println("Something went wrong!"); + throw new RuntimeException(error); + } else { + System.out.println("No more!"); + } + })); ``` ### Manual pagination -If none of the above helpers meet your needs, you can also manually request pages one-by-one. A page of results has a `data()` method to fetch the list of objects, as well as top-level `response` and other methods to fetch top-level data about the page. It also has methods `hasNextPage`, `getNextPage`, and `getNextPageParams` methods to help with pagination. +To access individual page items and manually request the next page, use the `items()`, +`hasNextPage()`, and `nextPage()` methods: ```java import com.openai.models.finetuning.jobs.FineTuningJob; import com.openai.models.finetuning.jobs.JobListPage; -JobListPage page = client.fineTuning().jobs().list(params); -while (page != null) { - for (FineTuningJob job : page.data()) { +JobListPage page = client.fineTuning().jobs().list(); +while (true) { + for (FineTuningJob job : page.items()) { System.out.println(job); } - page = page.getNextPage().orElse(null); + if (!page.hasNextPage()) { + break; + } + + page = page.nextPage(); } ``` @@ -607,7 +851,7 @@ If the SDK threw an exception, but you're _certain_ the version is compatible, t ## Microsoft Azure -To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the same +To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the same OpenAI client builder but with the Azure-specific configuration. ```java @@ -620,7 +864,7 @@ OpenAIClient client = OpenAIOkHttpClient.builder() .build(); ``` -See the complete Azure OpenAI example in the [`openai-java-example`](openai-java-example/src/main/java/com/openai/example/AzureEntraIdExample.java) directory. The other examples in the directory also work with Azure as long as the client is configured to use it. +See the complete Azure OpenAI example in the [`openai-java-example`](openai-java-example/src/main/java/com/openai/example/AzureEntraIdExample.java) directory. The other examples in the directory also work with Azure as long as the client is configured to use it. ## Network options @@ -657,9 +901,7 @@ Requests time out after 10 minutes by default. To set a custom timeout, configure the method call using the `timeout` method: ```java -import com.openai.models.ChatModel; import com.openai.models.chat.completions.ChatCompletion; -import com.openai.models.chat.completions.ChatCompletionCreateParams; ChatCompletion chatCompletion = client.chat().completions().create( params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() @@ -775,11 +1017,12 @@ To set a documented parameter or property to an undocumented or not yet supporte ```java import com.openai.core.JsonValue; +import com.openai.models.ChatModel; import com.openai.models.chat.completions.ChatCompletionCreateParams; ChatCompletionCreateParams params = ChatCompletionCreateParams.builder() - .addUserMessage("Say this is a test") - .model(JsonValue.from(42)) + .messages(JsonValue.from(42)) + .model(ChatModel.GPT_4_1) .build(); ``` @@ -909,9 +1152,7 @@ ChatCompletion chatCompletion = client.chat().completions().create(params).valid Or configure the method call to validate the response using the `responseValidation` method: ```java -import com.openai.models.ChatModel; import com.openai.models.chat.completions.ChatCompletion; -import com.openai.models.chat.completions.ChatCompletionCreateParams; ChatCompletion chatCompletion = client.chat().completions().create( params, RequestOptions.builder().responseValidation(true).build() diff --git a/openai-java-core/build.gradle.kts b/openai-java-core/build.gradle.kts index 08a91e0dc..894f0e234 100644 --- a/openai-java-core/build.gradle.kts +++ b/openai-java-core/build.gradle.kts @@ -27,6 +27,8 @@ dependencies { implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.18.2") implementation("org.apache.httpcomponents.core5:httpcore5:5.2.4") implementation("org.apache.httpcomponents.client5:httpclient5:5.3.1") + implementation("com.github.victools:jsonschema-generator:4.38.0") + implementation("com.github.victools:jsonschema-module-jackson:4.38.0") testImplementation(kotlin("test")) testImplementation(project(":openai-java-client-okhttp")) diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt index 3995c9ea9..e990bc66e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClient.kt @@ -11,6 +11,7 @@ import com.openai.services.blocking.EmbeddingService import com.openai.services.blocking.EvalService import com.openai.services.blocking.FileService import com.openai.services.blocking.FineTuningService +import com.openai.services.blocking.GraderService import com.openai.services.blocking.ImageService import com.openai.services.blocking.ModelService import com.openai.services.blocking.ModerationService @@ -65,6 +66,8 @@ interface OpenAIClient { fun fineTuning(): FineTuningService + fun graders(): GraderService + fun vectorStores(): VectorStoreService fun beta(): BetaService @@ -111,6 +114,8 @@ interface OpenAIClient { fun fineTuning(): FineTuningService.WithRawResponse + fun graders(): GraderService.WithRawResponse + fun vectorStores(): VectorStoreService.WithRawResponse fun beta(): BetaService.WithRawResponse diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt index 2a2d5894c..aff5f61eb 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsync.kt @@ -11,6 +11,7 @@ import com.openai.services.async.EmbeddingServiceAsync import com.openai.services.async.EvalServiceAsync import com.openai.services.async.FileServiceAsync import com.openai.services.async.FineTuningServiceAsync +import com.openai.services.async.GraderServiceAsync import com.openai.services.async.ImageServiceAsync import com.openai.services.async.ModelServiceAsync import com.openai.services.async.ModerationServiceAsync @@ -65,6 +66,8 @@ interface OpenAIClientAsync { fun fineTuning(): FineTuningServiceAsync + fun graders(): GraderServiceAsync + fun vectorStores(): VectorStoreServiceAsync fun beta(): BetaServiceAsync @@ -111,6 +114,8 @@ interface OpenAIClientAsync { fun fineTuning(): FineTuningServiceAsync.WithRawResponse + fun graders(): GraderServiceAsync.WithRawResponse + fun vectorStores(): VectorStoreServiceAsync.WithRawResponse fun beta(): BetaServiceAsync.WithRawResponse diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt index 2bbeb00bb..5e2719a6b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientAsyncImpl.kt @@ -22,6 +22,8 @@ import com.openai.services.async.FileServiceAsync import com.openai.services.async.FileServiceAsyncImpl import com.openai.services.async.FineTuningServiceAsync import com.openai.services.async.FineTuningServiceAsyncImpl +import com.openai.services.async.GraderServiceAsync +import com.openai.services.async.GraderServiceAsyncImpl import com.openai.services.async.ImageServiceAsync import com.openai.services.async.ImageServiceAsyncImpl import com.openai.services.async.ModelServiceAsync @@ -84,6 +86,10 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl FineTuningServiceAsyncImpl(clientOptionsWithUserAgent) } + private val graders: GraderServiceAsync by lazy { + GraderServiceAsyncImpl(clientOptionsWithUserAgent) + } + private val vectorStores: VectorStoreServiceAsync by lazy { VectorStoreServiceAsyncImpl(clientOptionsWithUserAgent) } @@ -126,6 +132,8 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl override fun fineTuning(): FineTuningServiceAsync = fineTuning + override fun graders(): GraderServiceAsync = graders + override fun vectorStores(): VectorStoreServiceAsync = vectorStores override fun beta(): BetaServiceAsync = beta @@ -179,6 +187,10 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl FineTuningServiceAsyncImpl.WithRawResponseImpl(clientOptions) } + private val graders: GraderServiceAsync.WithRawResponse by lazy { + GraderServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + private val vectorStores: VectorStoreServiceAsync.WithRawResponse by lazy { VectorStoreServiceAsyncImpl.WithRawResponseImpl(clientOptions) } @@ -221,6 +233,8 @@ class OpenAIClientAsyncImpl(private val clientOptions: ClientOptions) : OpenAICl override fun fineTuning(): FineTuningServiceAsync.WithRawResponse = fineTuning + override fun graders(): GraderServiceAsync.WithRawResponse = graders + override fun vectorStores(): VectorStoreServiceAsync.WithRawResponse = vectorStores override fun beta(): BetaServiceAsync.WithRawResponse = beta diff --git a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt index 17ad13b4f..c79edfecb 100644 --- a/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/client/OpenAIClientImpl.kt @@ -22,6 +22,8 @@ import com.openai.services.blocking.FileService import com.openai.services.blocking.FileServiceImpl import com.openai.services.blocking.FineTuningService import com.openai.services.blocking.FineTuningServiceImpl +import com.openai.services.blocking.GraderService +import com.openai.services.blocking.GraderServiceImpl import com.openai.services.blocking.ImageService import com.openai.services.blocking.ImageServiceImpl import com.openai.services.blocking.ModelService @@ -78,6 +80,8 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient FineTuningServiceImpl(clientOptionsWithUserAgent) } + private val graders: GraderService by lazy { GraderServiceImpl(clientOptionsWithUserAgent) } + private val vectorStores: VectorStoreService by lazy { VectorStoreServiceImpl(clientOptionsWithUserAgent) } @@ -116,6 +120,8 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient override fun fineTuning(): FineTuningService = fineTuning + override fun graders(): GraderService = graders + override fun vectorStores(): VectorStoreService = vectorStores override fun beta(): BetaService = beta @@ -169,6 +175,10 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient FineTuningServiceImpl.WithRawResponseImpl(clientOptions) } + private val graders: GraderService.WithRawResponse by lazy { + GraderServiceImpl.WithRawResponseImpl(clientOptions) + } + private val vectorStores: VectorStoreService.WithRawResponse by lazy { VectorStoreServiceImpl.WithRawResponseImpl(clientOptions) } @@ -211,6 +221,8 @@ class OpenAIClientImpl(private val clientOptions: ClientOptions) : OpenAIClient override fun fineTuning(): FineTuningService.WithRawResponse = fineTuning + override fun graders(): GraderService.WithRawResponse = graders + override fun vectorStores(): VectorStoreService.WithRawResponse = vectorStores override fun beta(): BetaService.WithRawResponse = beta diff --git a/openai-java-core/src/main/kotlin/com/openai/core/AutoPager.kt b/openai-java-core/src/main/kotlin/com/openai/core/AutoPager.kt new file mode 100644 index 000000000..888fd0347 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/AutoPager.kt @@ -0,0 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.core + +import java.util.stream.Stream +import java.util.stream.StreamSupport + +class AutoPager private constructor(private val firstPage: Page) : Iterable { + + companion object { + + fun from(firstPage: Page): AutoPager = AutoPager(firstPage) + } + + override fun iterator(): Iterator = + generateSequence(firstPage) { if (it.hasNextPage()) it.nextPage() else null } + .flatMap { it.items() } + .iterator() + + fun stream(): Stream = StreamSupport.stream(spliterator(), false) +} diff --git a/openai-java-core/src/main/kotlin/com/openai/core/AutoPagerAsync.kt b/openai-java-core/src/main/kotlin/com/openai/core/AutoPagerAsync.kt new file mode 100644 index 000000000..649be47c9 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/AutoPagerAsync.kt @@ -0,0 +1,88 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.core + +import com.openai.core.http.AsyncStreamResponse +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.concurrent.CompletionException +import java.util.concurrent.Executor +import java.util.concurrent.atomic.AtomicReference + +class AutoPagerAsync +private constructor(private val firstPage: PageAsync, private val defaultExecutor: Executor) : + AsyncStreamResponse { + + companion object { + + fun from(firstPage: PageAsync, defaultExecutor: Executor): AutoPagerAsync = + AutoPagerAsync(firstPage, defaultExecutor) + } + + private val onCompleteFuture = CompletableFuture() + private val state = AtomicReference(State.NEW) + + override fun subscribe(handler: AsyncStreamResponse.Handler): AsyncStreamResponse = + subscribe(handler, defaultExecutor) + + override fun subscribe( + handler: AsyncStreamResponse.Handler, + executor: Executor, + ): AsyncStreamResponse = apply { + // TODO(JDK): Use `compareAndExchange` once targeting JDK 9. + check(state.compareAndSet(State.NEW, State.SUBSCRIBED)) { + if (state.get() == State.SUBSCRIBED) "Cannot subscribe more than once" + else "Cannot subscribe after the response is closed" + } + + fun PageAsync.handle(): CompletableFuture { + if (state.get() == State.CLOSED) { + return CompletableFuture.completedFuture(null) + } + + items().forEach { handler.onNext(it) } + return if (hasNextPage()) nextPage().thenCompose { it.handle() } + else CompletableFuture.completedFuture(null) + } + + executor.execute { + firstPage.handle().whenComplete { _, error -> + val actualError = + if (error is CompletionException && error.cause != null) error.cause else error + try { + handler.onComplete(Optional.ofNullable(actualError)) + } finally { + try { + if (actualError == null) { + onCompleteFuture.complete(null) + } else { + onCompleteFuture.completeExceptionally(actualError) + } + } finally { + close() + } + } + } + } + } + + override fun onCompleteFuture(): CompletableFuture = onCompleteFuture + + override fun close() { + val previousState = state.getAndSet(State.CLOSED) + if (previousState == State.CLOSED) { + return + } + + // When the stream is closed, we should always consider it closed. If it closed due + // to an error, then we will have already completed the future earlier, and this + // will be a no-op. + onCompleteFuture.complete(null) + } +} + +private enum class State { + NEW, + SUBSCRIBED, + CLOSED, +} diff --git a/openai-java-core/src/main/kotlin/com/openai/core/Check.kt b/openai-java-core/src/main/kotlin/com/openai/core/Check.kt index dc411d75d..53b3b919e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/core/Check.kt +++ b/openai-java-core/src/main/kotlin/com/openai/core/Check.kt @@ -5,6 +5,9 @@ package com.openai.core import com.fasterxml.jackson.core.Version import com.fasterxml.jackson.core.util.VersionUtil +fun checkRequired(name: String, condition: Boolean) = + check(condition) { "`$name` is required, but was not set" } + fun checkRequired(name: String, value: T?): T = checkNotNull(value) { "`$name` is required, but was not set" } diff --git a/openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaLocalValidation.kt b/openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaLocalValidation.kt new file mode 100644 index 000000000..9a3ae7995 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaLocalValidation.kt @@ -0,0 +1,19 @@ +package com.openai.core + +/** + * Options for local validation of JSON schemas derived from arbitrary classes before a request is + * executed. + */ +enum class JsonSchemaLocalValidation { + /** + * Validate the JSON schema locally before the request is executed. The remote AI model will + * also validate the JSON schema. + */ + YES, + + /** + * Do not validate the JSON schema locally before the request is executed. The remote AI model + * will always validate the JSON schema. + */ + NO, +} diff --git a/openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaValidator.kt b/openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaValidator.kt new file mode 100644 index 000000000..85c20b43c --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/JsonSchemaValidator.kt @@ -0,0 +1,668 @@ +package com.openai.core + +import com.fasterxml.jackson.databind.JsonNode +import com.openai.core.JsonSchemaValidator.Companion.MAX_ENUM_TOTAL_STRING_LENGTH +import com.openai.core.JsonSchemaValidator.Companion.UNRESTRICTED_ENUM_VALUES_LIMIT + +/** + * A validator that ensures that a JSON schema complies with the rules and restrictions imposed by + * the OpenAI API specification for the input schemas used to define structured outputs. Only a + * subset of the JSON Schema language is supported. The purpose of this validator is to perform a + * quick check of a schema so that it can be determined to be likely to be accepted when passed in + * the request for an AI inference. + * + * This validator assumes that the JSON schema represents the structure of Java/Kotlin classes; it + * is not a general-purpose JSON schema validator. Assumptions are also made that the generator will + * be well-behaved, so the validation is not a check for strict conformance to the JSON Schema + * specification, but to the OpenAI API specification's restrictions on JSON schemas. + */ +internal class JsonSchemaValidator private constructor() { + + companion object { + // The names of the supported schema keywords. All other keywords will be rejected. + private const val SCHEMA = "\$schema" + private const val ID = "\$id" + private const val DEFS = "\$defs" + private const val REF = "\$ref" + private const val PROPS = "properties" + private const val ANY_OF = "anyOf" + private const val TYPE = "type" + private const val REQUIRED = "required" + private const val DESC = "description" + private const val TITLE = "title" + private const val ITEMS = "items" + private const val CONST = "const" + private const val ENUM = "enum" + private const val ADDITIONAL_PROPS = "additionalProperties" + + // The names of the supported schema data types. + // + // JSON Schema does not define an "integer" type, only a "number" type, but it allows any + // schema to define its own "vocabulary" of type names. "integer" is supported by OpenAI. + private const val TYPE_ARRAY = "array" + private const val TYPE_OBJECT = "object" + private const val TYPE_BOOLEAN = "boolean" + private const val TYPE_STRING = "string" + private const val TYPE_NUMBER = "number" + private const val TYPE_INTEGER = "integer" + private const val TYPE_NULL = "null" + + // The validator checks that unsupported type-specific keywords are not present in a + // property node. The OpenAI API specification states: + // + // "Notable keywords not supported include: + // + // - For strings: `minLength`, `maxLength`, `pattern`, `format` + // - For numbers: `minimum`, `maximum`, `multipleOf` + // - For objects: `patternProperties`, `unevaluatedProperties`, `propertyNames`, + // `minProperties`, `maxProperties` + // - For arrays: `unevaluatedItems`, `contains`, `minContains`, `maxContains`, `minItems`, + // `maxItems`, `uniqueItems`" + // + // As that list is not exhaustive, and no keywords are explicitly named as supported, this + // validation allows _no_ type-specific keywords. The following sets define the allowed + // keywords in different contexts and all others are rejected. + + /** + * The set of allowed keywords in the root schema only, not including the keywords that are + * also allowed in a sub-schema. + */ + private val ALLOWED_KEYWORDS_ROOT_SCHEMA_ONLY = setOf(SCHEMA, ID, DEFS) + + /** + * The set of allowed keywords when defining sub-schemas when the `"anyOf"` field is + * present. OpenAI allows the `"anyOf"` field in sub-schemas, but not in the root schema. + */ + private val ALLOWED_KEYWORDS_ANY_OF_SUB_SCHEMA = setOf(ANY_OF, TITLE, DESC) + + /** + * The set of allowed keywords when defining sub-schemas when the `"$ref"` field is present. + */ + private val ALLOWED_KEYWORDS_REF_SUB_SCHEMA = setOf(REF, TITLE, DESC) + + /** + * The set of allowed keywords when defining sub-schemas when the `"type"` field is set to + * `"object"`. + */ + private val ALLOWED_KEYWORDS_OBJECT_SUB_SCHEMA = + setOf(TYPE, REQUIRED, ADDITIONAL_PROPS, TITLE, DESC, PROPS) + + /** + * The set of allowed keywords when defining sub-schemas when the `"type"` field is set to + * `"array"`. + */ + private val ALLOWED_KEYWORDS_ARRAY_SUB_SCHEMA = setOf(TYPE, TITLE, DESC, ITEMS) + + /** + * The set of allowed keywords when defining sub-schemas when the `"type"` field is set to + * `"boolean"`, `"integer"`, `"number"`, or `"string"`. + */ + private val ALLOWED_KEYWORDS_SIMPLE_SUB_SCHEMA = setOf(TYPE, TITLE, DESC, ENUM, CONST) + + /** + * The maximum total length of all strings used in the schema for property names, definition + * names, enum values and const values. The OpenAI specification states: + * > In a schema, total string length of all property names, definition names, enum values, + * > and const values cannot exceed 15,000 characters. + */ + private const val MAX_TOTAL_STRING_LENGTH = 15_000 + + /** The maximum number of object properties allowed in a schema. */ + private const val MAX_OBJECT_PROPERTIES = 100 + + /** The maximum number of enum values across all enums in the schema. */ + private const val MAX_ENUM_VALUES = 500 + + /** + * The number of enum values in any one enum with string values beyond which a limit of + * [MAX_ENUM_TOTAL_STRING_LENGTH] is imposed on the total length of all the string values of + * that one enum. + */ + private const val UNRESTRICTED_ENUM_VALUES_LIMIT = 250 + + /** + * The maximum total length of all string values of a single enum where the number of values + * exceeds [UNRESTRICTED_ENUM_VALUES_LIMIT]. + */ + private const val MAX_ENUM_TOTAL_STRING_LENGTH = 7_500 + + /** The maximum depth (number of levels) of nesting allowed in a schema. */ + private const val MAX_NESTING_DEPTH = 5 + + /** The depth value that corresponds to the root level of the schema. */ + private const val ROOT_DEPTH = 0 + + /** + * The path string that identifies the root node in the schema when appearing in error + * messages or references. + */ + private const val ROOT_PATH = "#" + + /** + * Creates a new [JsonSchemaValidator]. After calling [validate], the validator instance + * holds information about the errors that occurred during validation (if any). A validator + * instance can be used only once to validate a schema; to validate another schema, create + * another validator. + */ + fun create() = JsonSchemaValidator() + } + + /** + * The total length of all strings used in the schema for property names, definition names, enum + * values and const values. + */ + private var totalStringLength: Int = 0 + + /** The total number of values across all enums in the schema. */ + private var totalEnumValues: Int = 0 + + /** The total number of object properties found in the schema, including in definitions. */ + private var totalObjectProperties: Int = 0 + + /** + * The set of valid references that may appear in the schema. This set includes the root schema + * and any definitions within the root schema. This is used to verify that references elsewhere + * in the schema are valid. This will always contain the root schema, but that may be the only + * member. + */ + private var validReferences: MutableSet = mutableSetOf(ROOT_PATH) + + /** The list of error messages accumulated during the validation process. */ + private val errors: MutableList = mutableListOf() + + /** + * Indicates if this validator has validated a schema or not. If a schema has been validated, + * this validator cannot be used again. + */ + private var isValidationComplete = false + + /** + * Gets the list of errors that were recorded during the validation pass. + * + * @return The list of errors. The list may be empty if no errors were recorded. In that case, + * the schema was found to be valid, or has not yet been validated by calling [validate]. + */ + fun errors(): List = errors.toImmutable() + + /** + * Indicates if a validated schema is valid or not. + * + * @return `true` if a schema has been validated by calling [validate] and no errors were + * reported; or `false` if errors were reported or if a schema has not yet been validated. + */ + fun isValid(): Boolean = isValidationComplete && errors.isEmpty() + + /** + * Validates a schema with respect to the OpenAI API specifications. + * + * @param rootSchema The root node of the tree representing the JSON schema definition. + * @return This schema validator for convenience, such as when chaining calls. + * @throws IllegalStateException If called a second time. Create a new validator to validate + * each new schema. + */ + fun validate(rootSchema: JsonNode): JsonSchemaValidator { + check(!isValidationComplete) { "Validation already complete." } + isValidationComplete = true + + validateSchema(rootSchema, ROOT_PATH, ROOT_DEPTH) + + // Verify total counts/lengths. These are not localized to a specific element in the schema, + // as no one element is the cause of the error; it is the combination of all elements that + // exceed the limits. Therefore, the root path is used in the error messages. + verify(totalEnumValues <= MAX_ENUM_VALUES, ROOT_PATH) { + "Total number of enum values ($totalEnumValues) exceeds limit of $MAX_ENUM_VALUES." + } + verify(totalStringLength <= MAX_TOTAL_STRING_LENGTH, ROOT_PATH) { + "Total string length of all values ($totalStringLength) exceeds " + + "limit of $MAX_TOTAL_STRING_LENGTH." + } + verify(totalObjectProperties <= MAX_OBJECT_PROPERTIES, ROOT_PATH) { + "Total number of object properties ($totalObjectProperties) exceeds " + + "limit of $MAX_OBJECT_PROPERTIES." + } + + return this + } + + /** + * Validates a schema. This may be the root schema or a sub-schema. Some validations are + * specific to the root schema, which is identified by the [depth] being equal to zero. + * + * This method is recursive: it will validate the given schema and any sub-schemas that it + * contains at any depth. References to other schemas (either the root schema or definition + * sub-schemas) do not increase the depth of nesting, as those references are not followed + * recursively, only checked to be valid internal schema references. + * + * @param schema The schema to be validated. This may be the root schema or any sub-schema. + * @param path The path that identifies the location of this schema within the JSON schema. For + * example, for the root schema, this will be `"#"`; for a definition sub-schema of a `Person` + * object, this will be `"#/$defs/Person"`. + * @param depth The current depth of nesting. The OpenAI API specification places a maximum + * limit on the depth of nesting, which will result in an error if it is exceeded. The nesting + * depth increases with each recursion into a nested sub-schema. For the root schema, the + * nesting depth is zero; all other sub-schemas will have a nesting depth greater than zero. + */ + private fun validateSchema(schema: JsonNode, path: String, depth: Int) { + verify(depth <= MAX_NESTING_DEPTH, path) { + "Current nesting depth is $depth, but maximum is $MAX_NESTING_DEPTH." + } + + verify(schema.isObject, path, { "Schema or sub-schema is not an object." }) { + // If the schema is not an object, perform no further validations. + return + } + + verify(!schema.isEmpty, path) { "Schema or sub-schema is empty." } + + if (depth == ROOT_DEPTH) { + // Sanity check for the presence of the "$schema" field, as this makes it more likely + // that the schema with `depth == 0` is actually the root node of a JSON schema, not + // just a generic JSON document that is being validated in error. + verify(schema.get(SCHEMA) != null, path) { "Root schema missing '$SCHEMA' field." } + } + + // Before sub-schemas can be validated, the list of definitions must be recorded to ensure + // that "$ref" references can be checked for validity. Definitions are optional and only + // appear in the root schema. + validateDefinitions(schema.get(DEFS), "$path/$DEFS", depth) + + val anyOf = schema.get(ANY_OF) + val type = schema.get(TYPE) + val ref = schema.get(REF) + + verify( + (anyOf != null).xor(type != null).xor(ref != null), + path, + { "Expected exactly one of '$TYPE' or '$ANY_OF' or '$REF'." }, + ) { + // Validation cannot continue if none are set, or if more than one is set. + return + } + + validateAnyOfSchema(schema, path, depth) + validateTypeSchema(schema, path, depth) + validateRefSchema(schema, path, depth) + } + + /** + * Validates a schema if it has an `"anyOf"` field. OpenAI does not support the use of `"anyOf"` + * at the root of a JSON schema. The value is the field is expected to be an array of valid + * sub-schemas. If the schema has no `"anyOf"` field, no action is taken. + */ + private fun validateAnyOfSchema(schema: JsonNode, path: String, depth: Int) { + val anyOf = schema.get(ANY_OF) + + if (anyOf == null) return + + validateKeywords(schema, ALLOWED_KEYWORDS_ANY_OF_SUB_SCHEMA, path, depth) + + verify( + anyOf.isArray && !anyOf.isEmpty, + path, + { "'$ANY_OF' field is not a non-empty array." }, + ) { + return + } + + // Validates that the root schema does not contain an `anyOf` field. This is a restriction + // imposed by the OpenAI API specification. `anyOf` fields _can_ appear at other depths. + verify(depth != ROOT_DEPTH, path) { "Root schema contains '$ANY_OF' field." } + + // Each entry must be a valid sub-schema. + anyOf.forEachIndexed { index, subSchema -> + validateSchema(subSchema, "$path/$ANY_OF[$index]", depth + 1) + } + } + + /** + * Validates a schema if it has a `"$ref"` field. The reference is checked to ensure it + * corresponds to a valid definition, or is a reference to the root schema. Recursive references + * are allowed. If no `"$ref"` field is found in the schema, no action is taken. + */ + private fun validateRefSchema(schema: JsonNode, path: String, depth: Int) { + val ref = schema.get(REF) + + if (ref == null) return + + validateKeywords(schema, ALLOWED_KEYWORDS_REF_SUB_SCHEMA, path, depth) + + val refPath = "$path/$REF" + + verify(ref.isTextual, refPath, { "'$REF' field is not a text value." }) { + // No point checking the reference has a referent if it is definitely malformed. + return + } + verify(ref.asText() in validReferences, refPath) { + "Invalid or unsupported reference: '${ref.asText()}'." + } + } + + /** + * Validates a schema if it has a `"type"` field. This includes most sub-schemas, except those + * that have a `"$ref"` or `"anyOf"` field instead. The `"type"` field may be set to a text + * value that is the name of the type (e.g., `"object"`, `"array"`, `"number"`), or it may be + * set to an array that contains two text values: the name of the type and `"null"`. The OpenAI + * API specification explains that this is how a property can be both required (i.e., it must + * appear in the JSON document), but its value can be optional (i.e., it can be set explicitly + * to `"null"`). If the schema has no `"type"` field, no action is taken. + */ + private fun validateTypeSchema(schema: JsonNode, path: String, depth: Int) { + val type = schema.get(TYPE) + + if (type == null) return + + val typeName = + if (type.isTextual) { + // Type will be something like `"type" : "string"` + type.asText() + } else if (type.isArray) { + // Type will be something like `"type" : [ "string", "null" ]`. This corresponds to + // the use of "Optional" in Java/Kotlin. + getTypeNameFromTypeArray(type, "$path/$TYPE") + } else { + error(path) { "'$TYPE' field is not a type name or array of type names." } + return + } + + when (typeName) { + TYPE_ARRAY -> validateArraySchema(schema, path, depth) + TYPE_OBJECT -> validateObjectSchema(schema, path, depth) + + TYPE_BOOLEAN, + TYPE_INTEGER, + TYPE_NUMBER, + TYPE_STRING -> validateSimpleSchema(schema, typeName, path, depth) + + // The type name could not be determined from a type name array. An error will already + // have been logged by `getTypeNameFromTypeArray`, so no need to do anything more here. + null -> return + + else -> error("$path/$TYPE") { "Unsupported '$TYPE' value: '$typeName'." } + } + } + + /** + * Validates a schema whose `"type"` is `"object"`. It is the responsibility of the caller to + * ensure that [schema] contains that type definition. If no type, or a different type is + * present, the behavior is not defined. + */ + private fun validateObjectSchema(schema: JsonNode, path: String, depth: Int) { + validateKeywords(schema, ALLOWED_KEYWORDS_OBJECT_SUB_SCHEMA, path, depth) + + // The schema must declare that additional properties are not allowed. For this check, it + // does not matter if there are no "properties" in the schema. + verify( + schema.get(ADDITIONAL_PROPS) != null && + schema.get(ADDITIONAL_PROPS).asBoolean() == false, + path, + ) { + "'$ADDITIONAL_PROPS' field is missing or is not set to 'false'." + } + + val properties = schema.get(PROPS) + + // The "properties" field may be missing (there may be no properties to declare), but if it + // is present, it must be a non-empty object, or validation cannot continue. + // TODO: Decide if a missing or empty "properties" field is OK or not. + verify( + properties == null || (properties.isObject && !properties.isEmpty), + path, + { "'$PROPS' field is not a non-empty object." }, + ) { + return + } + + if (properties != null) { // Must be an object. + // If a "properties" field is present, there must also be a "required" field. All + // properties must be named in the list of required properties. + validatePropertiesRequired( + properties.fieldNames().asSequence().toSet(), + schema.get(REQUIRED), + "$path/$REQUIRED", + ) + validateProperties(properties, "$path/$PROPS", depth) + } + } + + /** + * Validates a schema whose `"type"` is `"array"`. It is the responsibility of the caller to + * ensure that [schema] contains that type definition. If no type, or a different type is + * present, the behavior is not defined. + * + * An array schema must have an `"items"` field whose value is an object representing a valid + * sub-schema. + */ + private fun validateArraySchema(schema: JsonNode, path: String, depth: Int) { + validateKeywords(schema, ALLOWED_KEYWORDS_ARRAY_SUB_SCHEMA, path, depth) + + val items = schema.get(ITEMS) + + verify( + items != null && items.isObject, + path, + { "'$ITEMS' field is missing or is not an object." }, + ) { + return + } + + validateSchema(items, "$path/$ITEMS", depth + 1) + } + + /** + * Validates a schema whose `"type"` is one of the supported simple type names other than + * `"object"` and `"array"`. It is the responsibility of the caller to ensure that [schema] + * contains the correct type definition. If no type, or a different type is present, the + * behavior is not defined. + * + * @param typeName The name of the specific type of the schema. Where the field value is + * optional and the type is defined as an array of a type name and a `"null"`, this is the + * value of the non-`"null"` type name. For example `"string"`, or `"number"`. + */ + private fun validateSimpleSchema(schema: JsonNode, typeName: String, path: String, depth: Int) { + validateKeywords(schema, ALLOWED_KEYWORDS_SIMPLE_SUB_SCHEMA, path, depth) + + val enumField = schema.get(ENUM) + + // OpenAI API specification: "For a single enum property with string values, the total + // string length of all enum values cannot exceed 7,500 characters when there are more than + // 250 enum values." + val isString = typeName == TYPE_STRING + var numEnumValues = 0 + var stringLength = 0 + + enumField?.forEach { value -> + // OpenAI places limits on the total string length of all enum values across all enums + // without being specific about the type of those enums (unlike for enums with string + // values, which have their own restrictions noted above). The specification does not + // indicate how to count the string length for boolean or number values. Here it is + // assumed that their simple string representations should be counted. + val length = value.asText().length + + totalStringLength += length + totalEnumValues++ + + if (isString) { + numEnumValues++ + stringLength += length + } + } + + verify( + !isString || + numEnumValues <= UNRESTRICTED_ENUM_VALUES_LIMIT || + stringLength <= MAX_ENUM_TOTAL_STRING_LENGTH, + "$path/$ENUM", + ) { + "Total string length ($stringLength) of values of an enum with $numEnumValues " + + "values exceeds limit of $MAX_ENUM_TOTAL_STRING_LENGTH." + } + + schema.get(CONST)?.let { constValue -> totalStringLength += constValue.asText().length } + } + + /** + * Validates that the definitions (if present) contain fields that each define a valid schema. + * Records the names of any definitions to construct the set of possible valid references to + * those definitions. This set will be used to validate any references from within definition + * sub-schemas, or any other sub-schemas validated at a later time. + * + * @param defs The node containing the definitions. Definitions are optional, so this node may + * be `null`. Definitions may appear in the root schema, but will not appear in any + * sub-schemas. If no definitions are present, the list of valid references will not be + * changed and no errors will be recorded. + * @param path The path that identifies the location within the schema of the `"$defs"` node. + * @param depth The current depth of nesting. If definitions are present, this will be zero, as + * that is the depth of the root schema. + */ + private fun validateDefinitions(defs: JsonNode?, path: String, depth: Int) { + // Definitions are optional. If present, expect an object whose fields are named from the + // classes the definitions were extracted from. If not present, do not continue. + verify(defs == null || defs.isObject, path, { "'$DEFS' must be an object." }) { + return + } + + // First, record the valid references to definitions, as any definition sub-schema may + // contain a reference to any other definitions sub-schema (including itself) and those + // references need to be validated. + defs?.fieldNames()?.asSequence()?.forEach { defName -> + val reference = "$path/$defName" + + // Consider that there might be duplicate definition names if two different classes + // (from different packages) have the same simple name. That would be an error, but + // there is no need to stop the validations. + // TODO: How should duplicate names be handled? Will the generator use longer names? + verify(reference !in validReferences, path) { "Duplicate definition of '$defName'." } + validReferences += reference + } + + // Second, recursively validate the definition sub-schemas. + defs?.fieldNames()?.asSequence()?.forEach { defName -> + totalStringLength += defName.length + validateSchema(defs.get(defName), "$path/$DEFS/$defName", depth + 1) + } + } + + /** + * Validates that every property in a collection of property names appears in the array of + * property names in a `"required"` field. + * + * @param propertyNames The collection of property names to check in the array of required + * properties. This collection will not be empty. + * @param required The `"required"` field. This is expected to be a non-`null` array field with + * a set of property names. + * @param path The path identifying the location of the `"required"` field within the schema. + */ + private fun validatePropertiesRequired( + propertyNames: Collection, + required: JsonNode?, + path: String, + ) { + val requiredNames = required?.map { it.asText() }?.toSet() ?: emptySet() + + propertyNames.forEach { propertyName -> + verify(propertyName in requiredNames, path) { + "'$PROPS' field '$propertyName' is not listed as '$REQUIRED'." + } + } + } + + /** + * Validates that each named entry in the `"properties"` field of an object schema has a value + * that is a valid sub-schema. + * + * @param properties The `"properties"` field node of an object schema. + * @param path The path identifying the location of the `"properties"` field within the schema. + */ + private fun validateProperties(properties: JsonNode, path: String, depth: Int) { + val propertyNames = properties.fieldNames().asSequence().toList() + + propertyNames.forEach { propertyName -> + totalObjectProperties++ + totalStringLength += propertyName.length + validateSchema(properties.get(propertyName), "$path/$propertyName", depth + 1) + } + } + + /** + * Validates that the names of all fields in the given schema node are present in a collection + * of allowed keywords. + * + * @param depth The nesting depth of the [schema] node. If this depth is zero, an additional set + * of allowed keywords will be included automatically for keywords that are allowed to appear + * only at the root level of the schema (e.g., `"$schema"`, `"$defs"`). + */ + private fun validateKeywords( + schema: JsonNode, + allowedKeywords: Collection, + path: String, + depth: Int, + ) { + schema.fieldNames().forEach { keyword -> + verify( + keyword in allowedKeywords || + (depth == ROOT_DEPTH && keyword in ALLOWED_KEYWORDS_ROOT_SCHEMA_ONLY), + path, + ) { + "Use of '$keyword' is not supported here." + } + } + } + + /** + * Gets the name of a type from the given `"type"` field, where the field is an array that + * contains exactly two string values: a type name and a `"null"` (in any order). + * + * @param type The type node. This must be a field with an array value. If this is not an array + * field, the behavior is undefined. It is the responsibility of the caller to ensure that + * this function is only called for array fields. + * @return The type name in the array that is not the `"null"` type; or `null` if no such type + * name was found, or if the array does not contain exactly two expected values: the type name + * and a `"null"` type. If `null`, one or more validation errors will be recorded. + */ + private fun getTypeNameFromTypeArray(type: JsonNode, path: String): String? { + val types = type.asSequence().toList() + + if (types.size == 2 && types.all { it.isTextual }) { + // Allow one type name and one "null". Be lenient about the order. Assume that there are + // no oddities like type names that are empty strings, etc., as the schemas are expected + // to be generated. + if (types[1].asText() == TYPE_NULL && types[0].asText() != TYPE_NULL) { + return types[0].asText() + } else if (types[0].asText() == TYPE_NULL && types[1].asText() != TYPE_NULL) { + return types[1].asText() + } else { + error(path) { "Expected one type name and one \"$TYPE_NULL\"." } + } + } else { + error(path) { "Expected exactly two types, both strings." } + } + + return null + } + + private inline fun verify(value: Boolean, path: String, lazyMessage: () -> Any) { + verify(value, path, lazyMessage) {} + } + + private inline fun verify( + value: Boolean, + path: String, + lazyMessage: () -> Any, + onFalse: () -> Unit, + ) { + if (!value) { + error(path, lazyMessage) + onFalse() + } + } + + private inline fun error(path: String, lazyMessage: () -> Any) { + errors.add("$path: ${lazyMessage()}") + } + + override fun toString(): String = + "${javaClass.simpleName}{isValidationComplete=$isValidationComplete, " + + "totalStringLength=$totalStringLength, " + + "totalObjectProperties=$totalObjectProperties, " + + "totalEnumValues=$totalEnumValues, errors=$errors}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/core/Page.kt b/openai-java-core/src/main/kotlin/com/openai/core/Page.kt new file mode 100644 index 000000000..9c9560b41 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/Page.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.core + +/** + * An interface representing a single page, with items of type [T], from a paginated endpoint + * response. + * + * Implementations of this interface are expected to request additional pages synchronously. For + * asynchronous pagination, see the [PageAsync] interface. + */ +interface Page { + + /** + * Returns whether there's another page after this one. + * + * The method generally doesn't make requests so the result depends entirely on the data in this + * page. If a significant amount of time has passed between requesting this page and calling + * this method, then the result could be stale. + */ + fun hasNextPage(): Boolean + + /** + * Returns the page after this one by making another request. + * + * @throws IllegalStateException if it's impossible to get the next page. This exception is + * avoidable by calling [hasNextPage] first. + */ + fun nextPage(): Page + + /** Returns the items in this page. */ + fun items(): List +} diff --git a/openai-java-core/src/main/kotlin/com/openai/core/PageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/core/PageAsync.kt new file mode 100644 index 000000000..c67ff7916 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/PageAsync.kt @@ -0,0 +1,35 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.core + +import java.util.concurrent.CompletableFuture + +/** + * An interface representing a single page, with items of type [T], from a paginated endpoint + * response. + * + * Implementations of this interface are expected to request additional pages asynchronously. For + * synchronous pagination, see the [Page] interface. + */ +interface PageAsync { + + /** + * Returns whether there's another page after this one. + * + * The method generally doesn't make requests so the result depends entirely on the data in this + * page. If a significant amount of time has passed between requesting this page and calling + * this method, then the result could be stale. + */ + fun hasNextPage(): Boolean + + /** + * Returns the page after this one by making another request. + * + * @throws IllegalStateException if it's impossible to get the next page. This exception is + * avoidable by calling [hasNextPage] first. + */ + fun nextPage(): CompletableFuture> + + /** Returns the items in this page. */ + fun items(): List +} diff --git a/openai-java-core/src/main/kotlin/com/openai/core/StructuredOutputs.kt b/openai-java-core/src/main/kotlin/com/openai/core/StructuredOutputs.kt new file mode 100644 index 000000000..df48c1af2 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/core/StructuredOutputs.kt @@ -0,0 +1,132 @@ +package com.openai.core + +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.json.JsonMapper +import com.fasterxml.jackson.datatype.jdk8.Jdk8Module +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule +import com.fasterxml.jackson.module.kotlin.kotlinModule +import com.github.victools.jsonschema.generator.Option +import com.github.victools.jsonschema.generator.OptionPreset +import com.github.victools.jsonschema.generator.SchemaGenerator +import com.github.victools.jsonschema.generator.SchemaGeneratorConfigBuilder +import com.github.victools.jsonschema.module.jackson.JacksonModule +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.ResponseFormatJsonSchema +import com.openai.models.responses.ResponseFormatTextJsonSchemaConfig +import com.openai.models.responses.ResponseTextConfig + +// The SDK `ObjectMappers.jsonMapper()` requires that all fields of classes be marked with +// `@JsonProperty`, which is not desirable in this context, as it impedes usability. Therefore, a +// custom JSON mapper configuration is required. +private val MAPPER = + JsonMapper.builder() + .addModule(kotlinModule()) + .addModule(Jdk8Module()) + .addModule(JavaTimeModule()) + .build() + +/** + * Builds a response format using a JSON schema derived from the structure of an arbitrary Java + * class. + */ +@JvmSynthetic +internal fun responseFormatFromClass( + type: Class, + localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES, +): ResponseFormatJsonSchema = + ResponseFormatJsonSchema.builder() + .jsonSchema( + ResponseFormatJsonSchema.JsonSchema.builder() + .name("json-schema-from-${type.simpleName}") + .schema(JsonValue.fromJsonNode(extractAndValidateSchema(type, localValidation))) + // Ensure the model's output strictly adheres to this JSON schema. This is the + // essential "ON switch" for Structured Outputs. + .strict(true) + .build() + ) + .build() + +private fun extractAndValidateSchema( + type: Class, + localValidation: JsonSchemaLocalValidation, +): JsonNode { + val schema = extractSchema(type) + + if (localValidation == JsonSchemaLocalValidation.YES) { + val validator = JsonSchemaValidator.create().validate(schema) + + require(validator.isValid()) { + "Local validation failed for JSON schema derived from $type:\n" + + validator.errors().joinToString("\n") { " - $it" } + } + } + + return schema +} + +/** + * Builds a text configuration with its format set to a JSON schema derived from the structure of an + * arbitrary Java class. + */ +@JvmSynthetic +internal fun textConfigFromClass( + type: Class, + localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES, +): ResponseTextConfig = + ResponseTextConfig.builder() + .format( + ResponseFormatTextJsonSchemaConfig.builder() + .name("json-schema-from-${type.simpleName}") + .schema(JsonValue.fromJsonNode(extractAndValidateSchema(type, localValidation))) + // Ensure the model's output strictly adheres to this JSON schema. This is the + // essential "ON switch" for Structured Outputs. + .strict(true) + .build() + ) + .build() + +/** + * Derives a JSON schema from the structure of an arbitrary Java class. + * + * Validation is not performed by this function, as it allows extraction of the schema and + * validation of the schema to be controlled more easily when unit testing, as no exceptions will be + * thrown and any recorded validation errors can be inspected at leisure by the tests. + */ +@JvmSynthetic +internal fun extractSchema(type: Class): JsonNode { + val configBuilder = + SchemaGeneratorConfigBuilder( + com.github.victools.jsonschema.generator.SchemaVersion.DRAFT_2020_12, + OptionPreset.PLAIN_JSON, + ) + // Add `"additionalProperties" : false` to all object schemas (see OpenAI). + .with(Option.FORBIDDEN_ADDITIONAL_PROPERTIES_BY_DEFAULT) + // Use `JacksonModule` to support the use of Jackson annotations to set property and + // class names and descriptions and to mark fields with `@JsonIgnore`. + .with(JacksonModule()) + + configBuilder + .forFields() + // For OpenAI schemas, _all_ properties _must_ be required. Override the interpretation of + // the Jackson `required` parameter to the `@JsonProperty` annotation: it will always be + // assumed to be `true`, even if explicitly `false` and even if there is no `@JsonProperty` + // annotation present. + .withRequiredCheck { true } + + return SchemaGenerator(configBuilder.build()).generateSchema(type) +} + +/** + * Creates an instance of a Java class using data from a JSON. The JSON data should conform to the + * JSON schema previously extracted from the Java class. + */ +@JvmSynthetic +internal fun responseTypeFromJson(json: String, responseType: Class): T = + try { + MAPPER.readValue(json, responseType) + } catch (e: Exception) { + // The JSON document is included in the exception message to aid diagnosis of the problem. + // It is the responsibility of the SDK user to ensure that exceptions that may contain + // sensitive data are not exposed in logs. + throw OpenAIInvalidDataException("Error parsing JSON: $json", e) + } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegment.kt b/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegment.kt index ffd5f56d7..c2de7f04c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegment.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegment.kt @@ -21,13 +21,13 @@ import kotlin.jvm.optionals.getOrNull class TranscriptionSegment private constructor( private val id: JsonField, - private val avgLogprob: JsonField, - private val compressionRatio: JsonField, - private val end: JsonField, - private val noSpeechProb: JsonField, + private val avgLogprob: JsonField, + private val compressionRatio: JsonField, + private val end: JsonField, + private val noSpeechProb: JsonField, private val seek: JsonField, - private val start: JsonField, - private val temperature: JsonField, + private val start: JsonField, + private val temperature: JsonField, private val text: JsonField, private val tokens: JsonField>, private val additionalProperties: MutableMap, @@ -38,19 +38,19 @@ private constructor( @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), @JsonProperty("avg_logprob") @ExcludeMissing - avgLogprob: JsonField = JsonMissing.of(), + avgLogprob: JsonField = JsonMissing.of(), @JsonProperty("compression_ratio") @ExcludeMissing - compressionRatio: JsonField = JsonMissing.of(), - @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), + compressionRatio: JsonField = JsonMissing.of(), + @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), @JsonProperty("no_speech_prob") @ExcludeMissing - noSpeechProb: JsonField = JsonMissing.of(), + noSpeechProb: JsonField = JsonMissing.of(), @JsonProperty("seek") @ExcludeMissing seek: JsonField = JsonMissing.of(), - @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), + @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), @JsonProperty("temperature") @ExcludeMissing - temperature: JsonField = JsonMissing.of(), + temperature: JsonField = JsonMissing.of(), @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), @JsonProperty("tokens") @ExcludeMissing tokens: JsonField> = JsonMissing.of(), ) : this( @@ -81,7 +81,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun avgLogprob(): Double = avgLogprob.getRequired("avg_logprob") + fun avgLogprob(): Float = avgLogprob.getRequired("avg_logprob") /** * Compression ratio of the segment. If the value is greater than 2.4, consider the compression @@ -90,7 +90,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun compressionRatio(): Double = compressionRatio.getRequired("compression_ratio") + fun compressionRatio(): Float = compressionRatio.getRequired("compression_ratio") /** * End time of the segment in seconds. @@ -98,7 +98,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun end(): Double = end.getRequired("end") + fun end(): Float = end.getRequired("end") /** * Probability of no speech in the segment. If the value is higher than 1.0 and the @@ -107,7 +107,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun noSpeechProb(): Double = noSpeechProb.getRequired("no_speech_prob") + fun noSpeechProb(): Float = noSpeechProb.getRequired("no_speech_prob") /** * Seek offset of the segment. @@ -123,7 +123,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun start(): Double = start.getRequired("start") + fun start(): Float = start.getRequired("start") /** * Temperature parameter used for generating the segment. @@ -131,7 +131,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun temperature(): Double = temperature.getRequired("temperature") + fun temperature(): Float = temperature.getRequired("temperature") /** * Text content of the segment. @@ -161,7 +161,7 @@ private constructor( * * Unlike [avgLogprob], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("avg_logprob") @ExcludeMissing fun _avgLogprob(): JsonField = avgLogprob + @JsonProperty("avg_logprob") @ExcludeMissing fun _avgLogprob(): JsonField = avgLogprob /** * Returns the raw JSON value of [compressionRatio]. @@ -171,14 +171,14 @@ private constructor( */ @JsonProperty("compression_ratio") @ExcludeMissing - fun _compressionRatio(): JsonField = compressionRatio + fun _compressionRatio(): JsonField = compressionRatio /** * Returns the raw JSON value of [end]. * * Unlike [end], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end + @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end /** * Returns the raw JSON value of [noSpeechProb]. @@ -187,7 +187,7 @@ private constructor( */ @JsonProperty("no_speech_prob") @ExcludeMissing - fun _noSpeechProb(): JsonField = noSpeechProb + fun _noSpeechProb(): JsonField = noSpeechProb /** * Returns the raw JSON value of [seek]. @@ -201,14 +201,14 @@ private constructor( * * Unlike [start], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start + @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start /** * Returns the raw JSON value of [temperature]. * * Unlike [temperature], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("temperature") @ExcludeMissing fun _temperature(): JsonField = temperature + @JsonProperty("temperature") @ExcludeMissing fun _temperature(): JsonField = temperature /** * Returns the raw JSON value of [text]. @@ -262,13 +262,13 @@ private constructor( class Builder internal constructor() { private var id: JsonField? = null - private var avgLogprob: JsonField? = null - private var compressionRatio: JsonField? = null - private var end: JsonField? = null - private var noSpeechProb: JsonField? = null + private var avgLogprob: JsonField? = null + private var compressionRatio: JsonField? = null + private var end: JsonField? = null + private var noSpeechProb: JsonField? = null private var seek: JsonField? = null - private var start: JsonField? = null - private var temperature: JsonField? = null + private var start: JsonField? = null + private var temperature: JsonField? = null private var text: JsonField? = null private var tokens: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -303,60 +303,60 @@ private constructor( * Average logprob of the segment. If the value is lower than -1, consider the logprobs * failed. */ - fun avgLogprob(avgLogprob: Double) = avgLogprob(JsonField.of(avgLogprob)) + fun avgLogprob(avgLogprob: Float) = avgLogprob(JsonField.of(avgLogprob)) /** * Sets [Builder.avgLogprob] to an arbitrary JSON value. * - * You should usually call [Builder.avgLogprob] with a well-typed [Double] value instead. + * You should usually call [Builder.avgLogprob] with a well-typed [Float] value instead. * This method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun avgLogprob(avgLogprob: JsonField) = apply { this.avgLogprob = avgLogprob } + fun avgLogprob(avgLogprob: JsonField) = apply { this.avgLogprob = avgLogprob } /** * Compression ratio of the segment. If the value is greater than 2.4, consider the * compression failed. */ - fun compressionRatio(compressionRatio: Double) = + fun compressionRatio(compressionRatio: Float) = compressionRatio(JsonField.of(compressionRatio)) /** * Sets [Builder.compressionRatio] to an arbitrary JSON value. * - * You should usually call [Builder.compressionRatio] with a well-typed [Double] value + * You should usually call [Builder.compressionRatio] with a well-typed [Float] value * instead. This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun compressionRatio(compressionRatio: JsonField) = apply { + fun compressionRatio(compressionRatio: JsonField) = apply { this.compressionRatio = compressionRatio } /** End time of the segment in seconds. */ - fun end(end: Double) = end(JsonField.of(end)) + fun end(end: Float) = end(JsonField.of(end)) /** * Sets [Builder.end] to an arbitrary JSON value. * - * You should usually call [Builder.end] with a well-typed [Double] value instead. This + * You should usually call [Builder.end] with a well-typed [Float] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun end(end: JsonField) = apply { this.end = end } + fun end(end: JsonField) = apply { this.end = end } /** * Probability of no speech in the segment. If the value is higher than 1.0 and the * `avg_logprob` is below -1, consider this segment silent. */ - fun noSpeechProb(noSpeechProb: Double) = noSpeechProb(JsonField.of(noSpeechProb)) + fun noSpeechProb(noSpeechProb: Float) = noSpeechProb(JsonField.of(noSpeechProb)) /** * Sets [Builder.noSpeechProb] to an arbitrary JSON value. * - * You should usually call [Builder.noSpeechProb] with a well-typed [Double] value instead. + * You should usually call [Builder.noSpeechProb] with a well-typed [Float] value instead. * This method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun noSpeechProb(noSpeechProb: JsonField) = apply { + fun noSpeechProb(noSpeechProb: JsonField) = apply { this.noSpeechProb = noSpeechProb } @@ -372,27 +372,27 @@ private constructor( fun seek(seek: JsonField) = apply { this.seek = seek } /** Start time of the segment in seconds. */ - fun start(start: Double) = start(JsonField.of(start)) + fun start(start: Float) = start(JsonField.of(start)) /** * Sets [Builder.start] to an arbitrary JSON value. * - * You should usually call [Builder.start] with a well-typed [Double] value instead. This + * You should usually call [Builder.start] with a well-typed [Float] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun start(start: JsonField) = apply { this.start = start } + fun start(start: JsonField) = apply { this.start = start } /** Temperature parameter used for generating the segment. */ - fun temperature(temperature: Double) = temperature(JsonField.of(temperature)) + fun temperature(temperature: Float) = temperature(JsonField.of(temperature)) /** * Sets [Builder.temperature] to an arbitrary JSON value. * - * You should usually call [Builder.temperature] with a well-typed [Double] value instead. + * You should usually call [Builder.temperature] with a well-typed [Float] value instead. * This method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun temperature(temperature: JsonField) = apply { this.temperature = temperature } + fun temperature(temperature: JsonField) = apply { this.temperature = temperature } /** Text content of the segment. */ fun text(text: String) = text(JsonField.of(text)) diff --git a/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionWord.kt b/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionWord.kt index e17f25058..2ebd3c150 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionWord.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/audio/transcriptions/TranscriptionWord.kt @@ -17,16 +17,16 @@ import java.util.Objects class TranscriptionWord private constructor( - private val end: JsonField, - private val start: JsonField, + private val end: JsonField, + private val start: JsonField, private val word: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), - @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), + @JsonProperty("end") @ExcludeMissing end: JsonField = JsonMissing.of(), + @JsonProperty("start") @ExcludeMissing start: JsonField = JsonMissing.of(), @JsonProperty("word") @ExcludeMissing word: JsonField = JsonMissing.of(), ) : this(end, start, word, mutableMapOf()) @@ -36,7 +36,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun end(): Double = end.getRequired("end") + fun end(): Float = end.getRequired("end") /** * Start time of the word in seconds. @@ -44,7 +44,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun start(): Double = start.getRequired("start") + fun start(): Float = start.getRequired("start") /** * The text content of the word. @@ -59,14 +59,14 @@ private constructor( * * Unlike [end], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end + @JsonProperty("end") @ExcludeMissing fun _end(): JsonField = end /** * Returns the raw JSON value of [start]. * * Unlike [start], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start + @JsonProperty("start") @ExcludeMissing fun _start(): JsonField = start /** * Returns the raw JSON value of [word]. @@ -105,8 +105,8 @@ private constructor( /** A builder for [TranscriptionWord]. */ class Builder internal constructor() { - private var end: JsonField? = null - private var start: JsonField? = null + private var end: JsonField? = null + private var start: JsonField? = null private var word: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -119,26 +119,26 @@ private constructor( } /** End time of the word in seconds. */ - fun end(end: Double) = end(JsonField.of(end)) + fun end(end: Float) = end(JsonField.of(end)) /** * Sets [Builder.end] to an arbitrary JSON value. * - * You should usually call [Builder.end] with a well-typed [Double] value instead. This + * You should usually call [Builder.end] with a well-typed [Float] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun end(end: JsonField) = apply { this.end = end } + fun end(end: JsonField) = apply { this.end = end } /** Start time of the word in seconds. */ - fun start(start: Double) = start(JsonField.of(start)) + fun start(start: Float) = start(JsonField.of(start)) /** * Sets [Builder.start] to an arbitrary JSON value. * - * You should usually call [Builder.start] with a well-typed [Double] value instead. This + * You should usually call [Builder.start] with a well-typed [Float] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun start(start: JsonField) = apply { this.start = start } + fun start(start: JsonField) = apply { this.start = start } /** The text content of the word. */ fun word(word: String) = word(JsonField.of(word)) diff --git a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchCancelParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchCancelParams.kt index c9a0e7250..4fd0d88f5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchCancelParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchCancelParams.kt @@ -4,12 +4,12 @@ package com.openai.models.batches import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Cancels an in-progress batch. The batch will be in status `cancelling` for up to 10 minutes, @@ -18,13 +18,13 @@ import java.util.Optional */ class BatchCancelParams private constructor( - private val batchId: String, + private val batchId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun batchId(): String = batchId + fun batchId(): Optional = Optional.ofNullable(batchId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -36,14 +36,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [BatchCancelParams]. - * - * The following fields are required: - * ```java - * .batchId() - * ``` - */ + @JvmStatic fun none(): BatchCancelParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [BatchCancelParams]. */ @JvmStatic fun builder() = Builder() } @@ -63,7 +58,10 @@ private constructor( additionalBodyProperties = batchCancelParams.additionalBodyProperties.toMutableMap() } - fun batchId(batchId: String) = apply { this.batchId = batchId } + fun batchId(batchId: String?) = apply { this.batchId = batchId } + + /** Alias for calling [Builder.batchId] with `batchId.orElse(null)`. */ + fun batchId(batchId: Optional) = batchId(batchId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -189,17 +187,10 @@ private constructor( * Returns an immutable instance of [BatchCancelParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .batchId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): BatchCancelParams = BatchCancelParams( - checkRequired("batchId", batchId), + batchId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -211,7 +202,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> batchId + 0 -> batchId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPage.kt index 35c7aa3f1..d591ebcca 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.batches +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.BatchService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [BatchService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: BatchService, private val params: BatchListParams, private val response: BatchListPageResponse, -) { +) : Page { /** * Delegates to [BatchListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): BatchListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): BatchListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): BatchListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: BatchListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPageAsync.kt index 616127122..0b36c622f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.batches +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.BatchServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [BatchServiceAsync.list] */ class BatchListPageAsync private constructor( private val service: BatchServiceAsync, + private val streamHandlerExecutor: Executor, private val params: BatchListParams, private val response: BatchListPageResponse, -) { +) : PageAsync { /** * Delegates to [BatchListPageResponse], but gracefully handles missing data. @@ -33,22 +35,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): BatchListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): BatchListParams = params @@ -66,6 +62,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +74,24 @@ private constructor( class Builder internal constructor() { private var service: BatchServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: BatchListParams? = null private var response: BatchListPageResponse? = null @JvmSynthetic internal fun from(batchListPageAsync: BatchListPageAsync) = apply { service = batchListPageAsync.service + streamHandlerExecutor = batchListPageAsync.streamHandlerExecutor params = batchListPageAsync.params response = batchListPageAsync.response } fun service(service: BatchServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: BatchListParams) = apply { this.params = params } @@ -103,6 +106,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +116,22 @@ private constructor( fun build(): BatchListPageAsync = BatchListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: BatchListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (Batch) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is BatchListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is BatchListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "BatchListPageAsync{service=$service, params=$params, response=$response}" + "BatchListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchRetrieveParams.kt index 94571a8a2..d1667cc1d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/batches/BatchRetrieveParams.kt @@ -3,20 +3,21 @@ package com.openai.models.batches import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves a batch. */ class BatchRetrieveParams private constructor( - private val batchId: String, + private val batchId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun batchId(): String = batchId + fun batchId(): Optional = Optional.ofNullable(batchId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,14 +27,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [BatchRetrieveParams]. - * - * The following fields are required: - * ```java - * .batchId() - * ``` - */ + @JvmStatic fun none(): BatchRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [BatchRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -51,7 +47,10 @@ private constructor( additionalQueryParams = batchRetrieveParams.additionalQueryParams.toBuilder() } - fun batchId(batchId: String) = apply { this.batchId = batchId } + fun batchId(batchId: String?) = apply { this.batchId = batchId } + + /** Alias for calling [Builder.batchId] with `batchId.orElse(null)`. */ + fun batchId(batchId: Optional) = batchId(batchId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,25 +154,14 @@ private constructor( * Returns an immutable instance of [BatchRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .batchId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): BatchRetrieveParams = - BatchRetrieveParams( - checkRequired("batchId", batchId), - additionalHeaders.build(), - additionalQueryParams.build(), - ) + BatchRetrieveParams(batchId, additionalHeaders.build(), additionalQueryParams.build()) } fun _pathParam(index: Int): String = when (index) { - 0 -> batchId + 0 -> batchId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantDeleteParams.kt index f0c6d40fb..b5df03cb3 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantDeleteParams.kt @@ -4,23 +4,23 @@ package com.openai.models.beta.assistants import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Delete an assistant. */ class AssistantDeleteParams private constructor( - private val assistantId: String, + private val assistantId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun assistantId(): String = assistantId + fun assistantId(): Optional = Optional.ofNullable(assistantId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [AssistantDeleteParams]. - * - * The following fields are required: - * ```java - * .assistantId() - * ``` - */ + @JvmStatic fun none(): AssistantDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AssistantDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,7 +54,10 @@ private constructor( additionalBodyProperties = assistantDeleteParams.additionalBodyProperties.toMutableMap() } - fun assistantId(assistantId: String) = apply { this.assistantId = assistantId } + fun assistantId(assistantId: String?) = apply { this.assistantId = assistantId } + + /** Alias for calling [Builder.assistantId] with `assistantId.orElse(null)`. */ + fun assistantId(assistantId: Optional) = assistantId(assistantId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -185,17 +183,10 @@ private constructor( * Returns an immutable instance of [AssistantDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .assistantId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): AssistantDeleteParams = AssistantDeleteParams( - checkRequired("assistantId", assistantId), + assistantId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -207,7 +198,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> assistantId + 0 -> assistantId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPage.kt index c852b6fea..596b6fa64 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.beta.assistants +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.beta.AssistantService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [AssistantService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: AssistantService, private val params: AssistantListParams, private val response: AssistantListPageResponse, -) { +) : Page { /** * Delegates to [AssistantListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): AssistantListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): AssistantListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): AssistantListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: AssistantListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPageAsync.kt index 0e90b27c2..ce42fb78d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.beta.assistants +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.beta.AssistantServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [AssistantServiceAsync.list] */ class AssistantListPageAsync private constructor( private val service: AssistantServiceAsync, + private val streamHandlerExecutor: Executor, private val params: AssistantListParams, private val response: AssistantListPageResponse, -) { +) : PageAsync { /** * Delegates to [AssistantListPageResponse], but gracefully handles missing data. @@ -33,22 +35,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): AssistantListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): AssistantListParams = params @@ -66,6 +63,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +75,24 @@ private constructor( class Builder internal constructor() { private var service: AssistantServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: AssistantListParams? = null private var response: AssistantListPageResponse? = null @JvmSynthetic internal fun from(assistantListPageAsync: AssistantListPageAsync) = apply { service = assistantListPageAsync.service + streamHandlerExecutor = assistantListPageAsync.streamHandlerExecutor params = assistantListPageAsync.params response = assistantListPageAsync.response } fun service(service: AssistantServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: AssistantListParams) = apply { this.params = params } @@ -103,6 +107,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +117,22 @@ private constructor( fun build(): AssistantListPageAsync = AssistantListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: AssistantListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (Assistant) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is AssistantListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is AssistantListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "AssistantListPageAsync{service=$service, params=$params, response=$response}" + "AssistantListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantRetrieveParams.kt index 5ded97d81..7b9b07924 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantRetrieveParams.kt @@ -3,20 +3,21 @@ package com.openai.models.beta.assistants import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves an assistant. */ class AssistantRetrieveParams private constructor( - private val assistantId: String, + private val assistantId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun assistantId(): String = assistantId + fun assistantId(): Optional = Optional.ofNullable(assistantId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,14 +27,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [AssistantRetrieveParams]. - * - * The following fields are required: - * ```java - * .assistantId() - * ``` - */ + @JvmStatic fun none(): AssistantRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AssistantRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -51,7 +47,10 @@ private constructor( additionalQueryParams = assistantRetrieveParams.additionalQueryParams.toBuilder() } - fun assistantId(assistantId: String) = apply { this.assistantId = assistantId } + fun assistantId(assistantId: String?) = apply { this.assistantId = assistantId } + + /** Alias for calling [Builder.assistantId] with `assistantId.orElse(null)`. */ + fun assistantId(assistantId: Optional) = assistantId(assistantId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,17 +154,10 @@ private constructor( * Returns an immutable instance of [AssistantRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .assistantId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): AssistantRetrieveParams = AssistantRetrieveParams( - checkRequired("assistantId", assistantId), + assistantId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -173,7 +165,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> assistantId + 0 -> assistantId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantUpdateParams.kt index 92fcba310..24ae8550c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/assistants/AssistantUpdateParams.kt @@ -13,7 +13,6 @@ import com.openai.core.JsonMissing import com.openai.core.JsonValue import com.openai.core.Params import com.openai.core.checkKnown -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable @@ -32,13 +31,13 @@ import kotlin.jvm.optionals.getOrNull /** Modifies an assistant. */ class AssistantUpdateParams private constructor( - private val assistantId: String, + private val assistantId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun assistantId(): String = assistantId + fun assistantId(): Optional = Optional.ofNullable(assistantId) /** * The description of the assistant. The maximum length is 512 characters. @@ -253,14 +252,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [AssistantUpdateParams]. - * - * The following fields are required: - * ```java - * .assistantId() - * ``` - */ + @JvmStatic fun none(): AssistantUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [AssistantUpdateParams]. */ @JvmStatic fun builder() = Builder() } @@ -280,7 +274,10 @@ private constructor( additionalQueryParams = assistantUpdateParams.additionalQueryParams.toBuilder() } - fun assistantId(assistantId: String) = apply { this.assistantId = assistantId } + fun assistantId(assistantId: String?) = apply { this.assistantId = assistantId } + + /** Alias for calling [Builder.assistantId] with `assistantId.orElse(null)`. */ + fun assistantId(assistantId: Optional) = assistantId(assistantId.getOrNull()) /** * Sets the entire request body. @@ -723,17 +720,10 @@ private constructor( * Returns an immutable instance of [AssistantUpdateParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .assistantId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): AssistantUpdateParams = AssistantUpdateParams( - checkRequired("assistantId", assistantId), + assistantId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -744,7 +734,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> assistantId + 0 -> assistantId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadDeleteParams.kt index fd960288b..637a58534 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadDeleteParams.kt @@ -4,23 +4,23 @@ package com.openai.models.beta.threads import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Delete a thread. */ class ThreadDeleteParams private constructor( - private val threadId: String, + private val threadId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ThreadDeleteParams]. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - */ + @JvmStatic fun none(): ThreadDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ThreadDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,7 +54,10 @@ private constructor( additionalBodyProperties = threadDeleteParams.additionalBodyProperties.toMutableMap() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -185,17 +183,10 @@ private constructor( * Returns an immutable instance of [ThreadDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ThreadDeleteParams = ThreadDeleteParams( - checkRequired("threadId", threadId), + threadId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -207,7 +198,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadRetrieveParams.kt index 1d5bb1ae7..2ee637c69 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadRetrieveParams.kt @@ -3,20 +3,21 @@ package com.openai.models.beta.threads import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves a thread. */ class ThreadRetrieveParams private constructor( - private val threadId: String, + private val threadId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,14 +27,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ThreadRetrieveParams]. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - */ + @JvmStatic fun none(): ThreadRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ThreadRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -51,7 +47,10 @@ private constructor( additionalQueryParams = threadRetrieveParams.additionalQueryParams.toBuilder() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,25 +154,14 @@ private constructor( * Returns an immutable instance of [ThreadRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ThreadRetrieveParams = - ThreadRetrieveParams( - checkRequired("threadId", threadId), - additionalHeaders.build(), - additionalQueryParams.build(), - ) + ThreadRetrieveParams(threadId, additionalHeaders.build(), additionalQueryParams.build()) } fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadUpdateParams.kt index 3afece775..d6d639af8 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/ThreadUpdateParams.kt @@ -12,7 +12,6 @@ import com.openai.core.JsonMissing import com.openai.core.JsonValue import com.openai.core.Params import com.openai.core.checkKnown -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable @@ -25,13 +24,13 @@ import kotlin.jvm.optionals.getOrNull /** Modifies a thread. */ class ThreadUpdateParams private constructor( - private val threadId: String, + private val threadId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) /** * Set of 16 key-value pairs that can be attached to an object. This can be useful for storing @@ -80,14 +79,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ThreadUpdateParams]. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - */ + @JvmStatic fun none(): ThreadUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ThreadUpdateParams]. */ @JvmStatic fun builder() = Builder() } @@ -107,7 +101,10 @@ private constructor( additionalQueryParams = threadUpdateParams.additionalQueryParams.toBuilder() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) /** * Sets the entire request body. @@ -287,17 +284,10 @@ private constructor( * Returns an immutable instance of [ThreadUpdateParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ThreadUpdateParams = ThreadUpdateParams( - checkRequired("threadId", threadId), + threadId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -308,7 +298,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageCreateParams.kt index 6bf8f054c..caca9be56 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageCreateParams.kt @@ -38,13 +38,13 @@ import kotlin.jvm.optionals.getOrNull /** Create a message. */ class MessageCreateParams private constructor( - private val threadId: String, + private val threadId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) /** * The text contents of the message. @@ -130,7 +130,6 @@ private constructor( * * The following fields are required: * ```java - * .threadId() * .content() * .role() * ``` @@ -154,7 +153,10 @@ private constructor( additionalQueryParams = messageCreateParams.additionalQueryParams.toBuilder() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) /** * Sets the entire request body. @@ -378,7 +380,6 @@ private constructor( * * The following fields are required: * ```java - * .threadId() * .content() * .role() * ``` @@ -387,7 +388,7 @@ private constructor( */ fun build(): MessageCreateParams = MessageCreateParams( - checkRequired("threadId", threadId), + threadId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -398,7 +399,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageDeleteParams.kt index e20225101..9c79b7b31 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageDeleteParams.kt @@ -10,12 +10,13 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Deletes a message. */ class MessageDeleteParams private constructor( private val threadId: String, - private val messageId: String, + private val messageId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -23,7 +24,7 @@ private constructor( fun threadId(): String = threadId - fun messageId(): String = messageId + fun messageId(): Optional = Optional.ofNullable(messageId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -41,7 +42,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .messageId() * ``` */ @JvmStatic fun builder() = Builder() @@ -67,7 +67,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun messageId(messageId: String) = apply { this.messageId = messageId } + fun messageId(messageId: String?) = apply { this.messageId = messageId } + + /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ + fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -197,7 +200,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .messageId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -205,7 +207,7 @@ private constructor( fun build(): MessageDeleteParams = MessageDeleteParams( checkRequired("threadId", threadId), - checkRequired("messageId", messageId), + messageId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -218,7 +220,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> messageId + 1 -> messageId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPage.kt index 14a9a44dc..560ff950f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.beta.threads.messages +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.beta.threads.MessageService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [MessageService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: MessageService, private val params: MessageListParams, private val response: MessageListPageResponse, -) { +) : Page { /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): MessageListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): MessageListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): MessageListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: MessageListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPageAsync.kt index fd1595e31..8b6a0d4ea 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.beta.threads.messages +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.beta.threads.MessageServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [MessageServiceAsync.list] */ class MessageListPageAsync private constructor( private val service: MessageServiceAsync, + private val streamHandlerExecutor: Executor, private val params: MessageListParams, private val response: MessageListPageResponse, -) { +) : PageAsync { /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. @@ -33,22 +35,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): MessageListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): MessageListParams = params @@ -66,6 +63,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +75,24 @@ private constructor( class Builder internal constructor() { private var service: MessageServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: MessageListParams? = null private var response: MessageListPageResponse? = null @JvmSynthetic internal fun from(messageListPageAsync: MessageListPageAsync) = apply { service = messageListPageAsync.service + streamHandlerExecutor = messageListPageAsync.streamHandlerExecutor params = messageListPageAsync.params response = messageListPageAsync.response } fun service(service: MessageServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: MessageListParams) = apply { this.params = params } @@ -103,6 +107,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +117,22 @@ private constructor( fun build(): MessageListPageAsync = MessageListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: MessageListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (Message) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is MessageListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is MessageListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "MessageListPageAsync{service=$service, params=$params, response=$response}" + "MessageListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListParams.kt index 0a1f8bbbc..add2694aa 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageListParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.errors.OpenAIInvalidDataException @@ -17,7 +16,7 @@ import kotlin.jvm.optionals.getOrNull /** Returns a list of messages for a given thread. */ class MessageListParams private constructor( - private val threadId: String, + private val threadId: String?, private val after: String?, private val before: String?, private val limit: Long?, @@ -27,7 +26,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the list. @@ -66,14 +65,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [MessageListParams]. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - */ + @JvmStatic fun none(): MessageListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [MessageListParams]. */ @JvmStatic fun builder() = Builder() } @@ -101,7 +95,10 @@ private constructor( additionalQueryParams = messageListParams.additionalQueryParams.toBuilder() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the @@ -258,17 +255,10 @@ private constructor( * Returns an immutable instance of [MessageListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): MessageListParams = MessageListParams( - checkRequired("threadId", threadId), + threadId, after, before, limit, @@ -281,7 +271,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageRetrieveParams.kt index fc521fbfa..4c9cb0932 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageRetrieveParams.kt @@ -7,19 +7,21 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieve a message. */ class MessageRetrieveParams private constructor( private val threadId: String, - private val messageId: String, + private val messageId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun threadId(): String = threadId - fun messageId(): String = messageId + fun messageId(): Optional = Optional.ofNullable(messageId) fun _additionalHeaders(): Headers = additionalHeaders @@ -35,7 +37,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .messageId() * ``` */ @JvmStatic fun builder() = Builder() @@ -59,7 +60,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun messageId(messageId: String) = apply { this.messageId = messageId } + fun messageId(messageId: String?) = apply { this.messageId = messageId } + + /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ + fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -167,7 +171,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .messageId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -175,7 +178,7 @@ private constructor( fun build(): MessageRetrieveParams = MessageRetrieveParams( checkRequired("threadId", threadId), - checkRequired("messageId", messageId), + messageId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -184,7 +187,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> messageId + 1 -> messageId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageUpdateParams.kt index de35e85eb..302718712 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/messages/MessageUpdateParams.kt @@ -25,7 +25,7 @@ import kotlin.jvm.optionals.getOrNull class MessageUpdateParams private constructor( private val threadId: String, - private val messageId: String, + private val messageId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,7 +33,7 @@ private constructor( fun threadId(): String = threadId - fun messageId(): String = messageId + fun messageId(): Optional = Optional.ofNullable(messageId) /** * Set of 16 key-value pairs that can be attached to an object. This can be useful for storing @@ -71,7 +71,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .messageId() * ``` */ @JvmStatic fun builder() = Builder() @@ -97,7 +96,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun messageId(messageId: String) = apply { this.messageId = messageId } + fun messageId(messageId: String?) = apply { this.messageId = messageId } + + /** Alias for calling [Builder.messageId] with `messageId.orElse(null)`. */ + fun messageId(messageId: Optional) = messageId(messageId.getOrNull()) /** * Sets the entire request body. @@ -255,7 +257,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .messageId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -263,7 +264,7 @@ private constructor( fun build(): MessageUpdateParams = MessageUpdateParams( checkRequired("threadId", threadId), - checkRequired("messageId", messageId), + messageId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -275,7 +276,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> messageId + 1 -> messageId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCancelParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCancelParams.kt index cf442b6ca..ccb81100c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCancelParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCancelParams.kt @@ -10,12 +10,13 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Cancels a run that is `in_progress`. */ class RunCancelParams private constructor( private val threadId: String, - private val runId: String, + private val runId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -23,7 +24,7 @@ private constructor( fun threadId(): String = threadId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -41,7 +42,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -67,7 +67,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -197,7 +200,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -205,7 +207,7 @@ private constructor( fun build(): RunCancelParams = RunCancelParams( checkRequired("threadId", threadId), - checkRequired("runId", runId), + runId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -218,7 +220,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCreateParams.kt index 3d44da707..02f162705 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunCreateParams.kt @@ -52,14 +52,14 @@ import kotlin.jvm.optionals.getOrNull /** Create a run. */ class RunCreateParams private constructor( - private val threadId: String, + private val threadId: String?, private val include: List?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) /** * A list of additional fields to include in the response. Currently the only supported value is @@ -385,7 +385,6 @@ private constructor( * * The following fields are required: * ```java - * .threadId() * .assistantId() * ``` */ @@ -410,7 +409,10 @@ private constructor( additionalQueryParams = runCreateParams.additionalQueryParams.toBuilder() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) /** * A list of additional fields to include in the response. Currently the only supported @@ -1057,7 +1059,6 @@ private constructor( * * The following fields are required: * ```java - * .threadId() * .assistantId() * ``` * @@ -1065,7 +1066,7 @@ private constructor( */ fun build(): RunCreateParams = RunCreateParams( - checkRequired("threadId", threadId), + threadId, include?.toImmutable(), body.build(), additionalHeaders.build(), @@ -1077,7 +1078,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPage.kt index 108f1287e..206a0e6ae 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.beta.threads.runs +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.beta.threads.RunService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [RunService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: RunService, private val params: RunListParams, private val response: RunListPageResponse, -) { +) : Page { /** * Delegates to [RunListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): RunListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): RunListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): RunListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: RunListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPageAsync.kt index ca329d17d..e5e704662 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.beta.threads.runs +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.beta.threads.RunServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [RunServiceAsync.list] */ class RunListPageAsync private constructor( private val service: RunServiceAsync, + private val streamHandlerExecutor: Executor, private val params: RunListParams, private val response: RunListPageResponse, -) { +) : PageAsync { /** * Delegates to [RunListPageResponse], but gracefully handles missing data. @@ -33,22 +35,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): RunListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): RunListParams = params @@ -66,6 +62,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +74,24 @@ private constructor( class Builder internal constructor() { private var service: RunServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: RunListParams? = null private var response: RunListPageResponse? = null @JvmSynthetic internal fun from(runListPageAsync: RunListPageAsync) = apply { service = runListPageAsync.service + streamHandlerExecutor = runListPageAsync.streamHandlerExecutor params = runListPageAsync.params response = runListPageAsync.response } fun service(service: RunServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: RunListParams) = apply { this.params = params } @@ -103,6 +106,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +116,22 @@ private constructor( fun build(): RunListPageAsync = RunListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: RunListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (Run) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is RunListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is RunListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "RunListPageAsync{service=$service, params=$params, response=$response}" + "RunListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListParams.kt index 22d967142..cd4e0d5d1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunListParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.errors.OpenAIInvalidDataException @@ -17,7 +16,7 @@ import kotlin.jvm.optionals.getOrNull /** Returns a list of runs belonging to a thread. */ class RunListParams private constructor( - private val threadId: String, + private val threadId: String?, private val after: String?, private val before: String?, private val limit: Long?, @@ -26,7 +25,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun threadId(): String = threadId + fun threadId(): Optional = Optional.ofNullable(threadId) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the list. @@ -62,14 +61,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [RunListParams]. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - */ + @JvmStatic fun none(): RunListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [RunListParams]. */ @JvmStatic fun builder() = Builder() } @@ -95,7 +89,10 @@ private constructor( additionalQueryParams = runListParams.additionalQueryParams.toBuilder() } - fun threadId(threadId: String) = apply { this.threadId = threadId } + fun threadId(threadId: String?) = apply { this.threadId = threadId } + + /** Alias for calling [Builder.threadId] with `threadId.orElse(null)`. */ + fun threadId(threadId: Optional) = threadId(threadId.getOrNull()) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the @@ -246,17 +243,10 @@ private constructor( * Returns an immutable instance of [RunListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .threadId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): RunListParams = RunListParams( - checkRequired("threadId", threadId), + threadId, after, before, limit, @@ -268,7 +258,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> threadId + 0 -> threadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunRetrieveParams.kt index 850f086c4..1ffc8e41f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunRetrieveParams.kt @@ -7,19 +7,21 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves a run. */ class RunRetrieveParams private constructor( private val threadId: String, - private val runId: String, + private val runId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun threadId(): String = threadId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) fun _additionalHeaders(): Headers = additionalHeaders @@ -35,7 +37,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -59,7 +60,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -167,7 +171,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -175,7 +178,7 @@ private constructor( fun build(): RunRetrieveParams = RunRetrieveParams( checkRequired("threadId", threadId), - checkRequired("runId", runId), + runId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -184,7 +187,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunSubmitToolOutputsParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunSubmitToolOutputsParams.kt index 38e059987..8b23d6c91 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunSubmitToolOutputsParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunSubmitToolOutputsParams.kt @@ -30,7 +30,7 @@ import kotlin.jvm.optionals.getOrNull class RunSubmitToolOutputsParams private constructor( private val threadId: String, - private val runId: String, + private val runId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -38,7 +38,7 @@ private constructor( fun threadId(): String = threadId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) /** * A list of tools for which the outputs are being submitted. @@ -71,7 +71,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * .toolOutputs() * ``` */ @@ -98,7 +97,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) /** * Sets the entire request body. @@ -255,7 +257,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * .toolOutputs() * ``` * @@ -264,7 +265,7 @@ private constructor( fun build(): RunSubmitToolOutputsParams = RunSubmitToolOutputsParams( checkRequired("threadId", threadId), - checkRequired("runId", runId), + runId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -276,7 +277,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunUpdateParams.kt index b93a12350..21ecf31a5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/RunUpdateParams.kt @@ -25,7 +25,7 @@ import kotlin.jvm.optionals.getOrNull class RunUpdateParams private constructor( private val threadId: String, - private val runId: String, + private val runId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,7 +33,7 @@ private constructor( fun threadId(): String = threadId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) /** * Set of 16 key-value pairs that can be attached to an object. This can be useful for storing @@ -71,7 +71,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -97,7 +96,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) /** * Sets the entire request body. @@ -255,7 +257,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -263,7 +264,7 @@ private constructor( fun build(): RunUpdateParams = RunUpdateParams( checkRequired("threadId", threadId), - checkRequired("runId", runId), + runId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -275,7 +276,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPage.kt index b9740fabf..353febb1f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.beta.threads.runs.steps +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.beta.threads.runs.StepService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [StepService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: StepService, private val params: StepListParams, private val response: StepListPageResponse, -) { +) : Page { /** * Delegates to [StepListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): StepListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): StepListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): StepListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: StepListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPageAsync.kt index a753633ed..8e5b30095 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.beta.threads.runs.steps +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.beta.threads.runs.StepServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [StepServiceAsync.list] */ class StepListPageAsync private constructor( private val service: StepServiceAsync, + private val streamHandlerExecutor: Executor, private val params: StepListParams, private val response: StepListPageResponse, -) { +) : PageAsync { /** * Delegates to [StepListPageResponse], but gracefully handles missing data. @@ -33,22 +35,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): StepListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): StepListParams = params @@ -66,6 +62,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +74,24 @@ private constructor( class Builder internal constructor() { private var service: StepServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: StepListParams? = null private var response: StepListPageResponse? = null @JvmSynthetic internal fun from(stepListPageAsync: StepListPageAsync) = apply { service = stepListPageAsync.service + streamHandlerExecutor = stepListPageAsync.streamHandlerExecutor params = stepListPageAsync.params response = stepListPageAsync.response } fun service(service: StepServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: StepListParams) = apply { this.params = params } @@ -103,6 +106,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +116,22 @@ private constructor( fun build(): StepListPageAsync = StepListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: StepListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (RunStep) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is StepListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is StepListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "StepListPageAsync{service=$service, params=$params, response=$response}" + "StepListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListParams.kt index ca18dea9b..c88cb3ef2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepListParams.kt @@ -19,7 +19,7 @@ import kotlin.jvm.optionals.getOrNull class StepListParams private constructor( private val threadId: String, - private val runId: String, + private val runId: String?, private val after: String?, private val before: String?, private val include: List?, @@ -31,7 +31,7 @@ private constructor( fun threadId(): String = threadId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the list. @@ -84,7 +84,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -118,7 +117,10 @@ private constructor( fun threadId(threadId: String) = apply { this.threadId = threadId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the @@ -298,7 +300,6 @@ private constructor( * The following fields are required: * ```java * .threadId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -306,7 +307,7 @@ private constructor( fun build(): StepListParams = StepListParams( checkRequired("threadId", threadId), - checkRequired("runId", runId), + runId, after, before, include?.toImmutable(), @@ -320,7 +321,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> threadId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepRetrieveParams.kt index 15275de57..c42a51a5d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/beta/threads/runs/steps/StepRetrieveParams.kt @@ -16,7 +16,7 @@ class StepRetrieveParams private constructor( private val threadId: String, private val runId: String, - private val stepId: String, + private val stepId: String?, private val include: List?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -26,7 +26,7 @@ private constructor( fun runId(): String = runId - fun stepId(): String = stepId + fun stepId(): Optional = Optional.ofNullable(stepId) /** * A list of additional fields to include in the response. Currently the only supported value is @@ -54,7 +54,6 @@ private constructor( * ```java * .threadId() * .runId() - * .stepId() * ``` */ @JvmStatic fun builder() = Builder() @@ -84,7 +83,10 @@ private constructor( fun runId(runId: String) = apply { this.runId = runId } - fun stepId(stepId: String) = apply { this.stepId = stepId } + fun stepId(stepId: String?) = apply { this.stepId = stepId } + + /** Alias for calling [Builder.stepId] with `stepId.orElse(null)`. */ + fun stepId(stepId: Optional) = stepId(stepId.getOrNull()) /** * A list of additional fields to include in the response. Currently the only supported @@ -218,7 +220,6 @@ private constructor( * ```java * .threadId() * .runId() - * .stepId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -227,7 +228,7 @@ private constructor( StepRetrieveParams( checkRequired("threadId", threadId), checkRequired("runId", runId), - checkRequired("stepId", stepId), + stepId, include?.toImmutable(), additionalHeaders.build(), additionalQueryParams.build(), @@ -238,7 +239,7 @@ private constructor( when (index) { 0 -> threadId 1 -> runId - 2 -> stepId + 2 -> stepId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt index a3281dc66..85d2582fe 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParams.kt @@ -19,6 +19,7 @@ import com.openai.core.Enum import com.openai.core.ExcludeMissing import com.openai.core.JsonField import com.openai.core.JsonMissing +import com.openai.core.JsonSchemaLocalValidation import com.openai.core.JsonValue import com.openai.core.Params import com.openai.core.allMaxBy @@ -1297,6 +1298,31 @@ private constructor( body.responseFormat(jsonObject) } + /** + * Sets the response format to a JSON schema derived from the structure of the given class. + * This changes the builder to a type-safe [StructuredChatCompletionCreateParams.Builder] + * that will build a [StructuredChatCompletionCreateParams] instance when `build()` is + * called. + * + * @param responseType A class from which a JSON schema will be derived to define the + * response format. + * @param localValidation [com.openai.core.JsonSchemaLocalValidation.YES] (the default) to + * validate the JSON schema locally when it is generated by this method to confirm that it + * adheres to the requirements and restrictions on JSON schemas imposed by the OpenAI + * specification; or [com.openai.core.JsonSchemaLocalValidation.NO] to skip local + * validation and rely only on remote validation. See the SDK documentation for more + * details. + * @throws IllegalArgumentException If local validation is enabled, but it fails because a + * valid JSON schema cannot be derived from the given class. + */ + @JvmOverloads + fun responseFormat( + responseType: Class, + localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES, + ) = + StructuredChatCompletionCreateParams.builder() + .wrap(responseType, this, localValidation) + /** * This feature is in Beta. If specified, our system will make a best effort to sample * deterministically, such that repeated requests with the same `seed` and parameters should diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionDeleteParams.kt index 0cd4d7faa..64f6792e1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionDeleteParams.kt @@ -4,12 +4,12 @@ package com.openai.models.chat.completions import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Delete a stored chat completion. Only Chat Completions that have been created with the `store` @@ -17,13 +17,13 @@ import java.util.Optional */ class ChatCompletionDeleteParams private constructor( - private val completionId: String, + private val completionId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun completionId(): String = completionId + fun completionId(): Optional = Optional.ofNullable(completionId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -35,13 +35,10 @@ private constructor( companion object { + @JvmStatic fun none(): ChatCompletionDeleteParams = builder().build() + /** * Returns a mutable builder for constructing an instance of [ChatCompletionDeleteParams]. - * - * The following fields are required: - * ```java - * .completionId() - * ``` */ @JvmStatic fun builder() = Builder() } @@ -63,7 +60,10 @@ private constructor( chatCompletionDeleteParams.additionalBodyProperties.toMutableMap() } - fun completionId(completionId: String) = apply { this.completionId = completionId } + fun completionId(completionId: String?) = apply { this.completionId = completionId } + + /** Alias for calling [Builder.completionId] with `completionId.orElse(null)`. */ + fun completionId(completionId: Optional) = completionId(completionId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -189,17 +189,10 @@ private constructor( * Returns an immutable instance of [ChatCompletionDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .completionId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ChatCompletionDeleteParams = ChatCompletionDeleteParams( - checkRequired("completionId", completionId), + completionId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -211,7 +204,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> completionId + 0 -> completionId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPage.kt index 6c807633b..a0c724746 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.chat.completions +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.chat.ChatCompletionService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [ChatCompletionService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: ChatCompletionService, private val params: ChatCompletionListParams, private val response: ChatCompletionListPageResponse, -) { +) : Page { /** * Delegates to [ChatCompletionListPageResponse], but gracefully handles missing data. @@ -33,20 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): ChatCompletionListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = - getNextPageParams().map { service.list(it) } + override fun nextPage(): ChatCompletionListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): ChatCompletionListParams = params @@ -115,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: ChatCompletionListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPageAsync.kt index 87bef9ed9..ebd91537c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.chat.completions +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.chat.ChatCompletionServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [ChatCompletionServiceAsync.list] */ class ChatCompletionListPageAsync private constructor( private val service: ChatCompletionServiceAsync, + private val streamHandlerExecutor: Executor, private val params: ChatCompletionListParams, private val response: ChatCompletionListPageResponse, -) { +) : PageAsync { /** * Delegates to [ChatCompletionListPageResponse], but gracefully handles missing data. @@ -34,22 +36,18 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): ChatCompletionListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): ChatCompletionListParams = params @@ -67,6 +65,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +77,24 @@ private constructor( class Builder internal constructor() { private var service: ChatCompletionServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: ChatCompletionListParams? = null private var response: ChatCompletionListPageResponse? = null @JvmSynthetic internal fun from(chatCompletionListPageAsync: ChatCompletionListPageAsync) = apply { service = chatCompletionListPageAsync.service + streamHandlerExecutor = chatCompletionListPageAsync.streamHandlerExecutor params = chatCompletionListPageAsync.params response = chatCompletionListPageAsync.response } fun service(service: ChatCompletionServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: ChatCompletionListParams) = apply { this.params = params } @@ -104,6 +109,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +119,22 @@ private constructor( fun build(): ChatCompletionListPageAsync = ChatCompletionListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: ChatCompletionListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (ChatCompletion) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ChatCompletionListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is ChatCompletionListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "ChatCompletionListPageAsync{service=$service, params=$params, response=$response}" + "ChatCompletionListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionRetrieveParams.kt index adf67c89d..5254f338b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionRetrieveParams.kt @@ -3,10 +3,11 @@ package com.openai.models.chat.completions import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Get a stored chat completion. Only Chat Completions that have been created with the `store` @@ -14,12 +15,12 @@ import java.util.Objects */ class ChatCompletionRetrieveParams private constructor( - private val completionId: String, + private val completionId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun completionId(): String = completionId + fun completionId(): Optional = Optional.ofNullable(completionId) fun _additionalHeaders(): Headers = additionalHeaders @@ -29,13 +30,10 @@ private constructor( companion object { + @JvmStatic fun none(): ChatCompletionRetrieveParams = builder().build() + /** * Returns a mutable builder for constructing an instance of [ChatCompletionRetrieveParams]. - * - * The following fields are required: - * ```java - * .completionId() - * ``` */ @JvmStatic fun builder() = Builder() } @@ -54,7 +52,10 @@ private constructor( additionalQueryParams = chatCompletionRetrieveParams.additionalQueryParams.toBuilder() } - fun completionId(completionId: String) = apply { this.completionId = completionId } + fun completionId(completionId: String?) = apply { this.completionId = completionId } + + /** Alias for calling [Builder.completionId] with `completionId.orElse(null)`. */ + fun completionId(completionId: Optional) = completionId(completionId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -158,17 +159,10 @@ private constructor( * Returns an immutable instance of [ChatCompletionRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .completionId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ChatCompletionRetrieveParams = ChatCompletionRetrieveParams( - checkRequired("completionId", completionId), + completionId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -176,7 +170,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> completionId + 0 -> completionId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionUpdateParams.kt index 953298850..6468e4e71 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/ChatCompletionUpdateParams.kt @@ -28,13 +28,13 @@ import kotlin.jvm.optionals.getOrNull */ class ChatCompletionUpdateParams private constructor( - private val completionId: String, + private val completionId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun completionId(): String = completionId + fun completionId(): Optional = Optional.ofNullable(completionId) /** * Set of 16 key-value pairs that can be attached to an object. This can be useful for storing @@ -71,7 +71,6 @@ private constructor( * * The following fields are required: * ```java - * .completionId() * .metadata() * ``` */ @@ -94,7 +93,10 @@ private constructor( additionalQueryParams = chatCompletionUpdateParams.additionalQueryParams.toBuilder() } - fun completionId(completionId: String) = apply { this.completionId = completionId } + fun completionId(completionId: String?) = apply { this.completionId = completionId } + + /** Alias for calling [Builder.completionId] with `completionId.orElse(null)`. */ + fun completionId(completionId: Optional) = completionId(completionId.getOrNull()) /** * Sets the entire request body. @@ -251,7 +253,6 @@ private constructor( * * The following fields are required: * ```java - * .completionId() * .metadata() * ``` * @@ -259,7 +260,7 @@ private constructor( */ fun build(): ChatCompletionUpdateParams = ChatCompletionUpdateParams( - checkRequired("completionId", completionId), + completionId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -270,7 +271,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> completionId + 0 -> completionId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletion.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletion.kt new file mode 100644 index 000000000..872135a4c --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletion.kt @@ -0,0 +1,176 @@ +package com.openai.models.chat.completions + +import com.openai.core.JsonField +import com.openai.core.JsonValue +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.chat.completions.ChatCompletion.Choice.FinishReason +import com.openai.models.chat.completions.ChatCompletion.Choice.Logprobs +import com.openai.models.chat.completions.ChatCompletion.ServiceTier +import com.openai.models.completions.CompletionUsage +import java.util.Objects +import java.util.Optional + +/** + * A wrapper for [ChatCompletion] that provides type-safe access to the [choices] when using the + * _Structured Outputs_ feature to deserialize a JSON response to an instance of an arbitrary class. + * See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class to which the JSON data in the response will be deserialized. + */ +class StructuredChatCompletion( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawChatCompletion") val rawChatCompletion: ChatCompletion, +) { + /** @see ChatCompletion.id */ + fun id(): String = rawChatCompletion.id() + + private val choices by lazy { + rawChatCompletion._choices().map { choices -> choices.map { Choice(responseType, it) } } + } + + /** @see ChatCompletion.choices */ + fun choices(): List> = choices.getRequired("choices") + + /** @see ChatCompletion.created */ + fun created(): Long = rawChatCompletion.created() + + /** @see ChatCompletion.model */ + fun model(): String = rawChatCompletion.model() + + /** @see ChatCompletion._object_ */ + fun _object_(): JsonValue = rawChatCompletion._object_() + + /** @see ChatCompletion.serviceTier */ + fun serviceTier(): Optional = rawChatCompletion.serviceTier() + + /** @see ChatCompletion.systemFingerprint */ + fun systemFingerprint(): Optional = rawChatCompletion.systemFingerprint() + + /** @see ChatCompletion.usage */ + fun usage(): Optional = rawChatCompletion.usage() + + /** @see ChatCompletion._id */ + fun _id(): JsonField = rawChatCompletion._id() + + /** @see ChatCompletion._choices */ + fun _choices(): JsonField>> = choices + + /** @see ChatCompletion._created */ + fun _created(): JsonField = rawChatCompletion._created() + + /** @see ChatCompletion._model */ + fun _model(): JsonField = rawChatCompletion._model() + + /** @see ChatCompletion._serviceTier */ + fun _serviceTier(): JsonField = rawChatCompletion._serviceTier() + + /** @see ChatCompletion._systemFingerprint */ + fun _systemFingerprint(): JsonField = rawChatCompletion._systemFingerprint() + + /** @see ChatCompletion._usage */ + fun _usage(): JsonField = rawChatCompletion._usage() + + /** @see ChatCompletion._additionalProperties */ + fun _additionalProperties(): Map = rawChatCompletion._additionalProperties() + + class Choice + internal constructor( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawChoice") val rawChoice: ChatCompletion.Choice, + ) { + /** @see ChatCompletion.Choice.finishReason */ + fun finishReason(): FinishReason = rawChoice.finishReason() + + /** @see ChatCompletion.Choice.index */ + fun index(): Long = rawChoice.index() + + /** @see ChatCompletion.Choice.logprobs */ + fun logprobs(): Optional = rawChoice.logprobs() + + /** @see ChatCompletion.Choice._finishReason */ + fun _finishReason(): JsonField = rawChoice._finishReason() + + private val message by lazy { + rawChoice._message().map { StructuredChatCompletionMessage(responseType, it) } + } + + /** @see ChatCompletion.Choice.message */ + fun message(): StructuredChatCompletionMessage = message.getRequired("message") + + /** @see ChatCompletion.Choice._index */ + fun _index(): JsonField = rawChoice._index() + + /** @see ChatCompletion.Choice._logprobs */ + fun _logprobs(): JsonField = rawChoice._logprobs() + + /** @see ChatCompletion.Choice._message */ + fun _message(): JsonField> = message + + /** @see ChatCompletion.Choice._additionalProperties */ + fun _additionalProperties(): Map = rawChoice._additionalProperties() + + /** @see ChatCompletion.Choice.validate */ + fun validate(): Choice = apply { + message().validate() + rawChoice.validate() + } + + /** @see ChatCompletion.Choice.isValid */ + fun isValid(): Boolean = + try { + validate() + true + } catch (_: OpenAIInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Choice<*> && + responseType == other.responseType && + rawChoice == other.rawChoice + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawChoice) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "${javaClass.simpleName}{responseType=$responseType, rawChoice=$rawChoice}" + } + + /** @see ChatCompletion.validate */ + fun validate() = apply { + choices().forEach { it.validate() } + rawChatCompletion.validate() + } + + /** @see ChatCompletion.isValid */ + fun isValid(): Boolean = + try { + validate() + true + } catch (_: OpenAIInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StructuredChatCompletion<*> && + responseType == other.responseType && + rawChatCompletion == other.rawChatCompletion + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawChatCompletion) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "${javaClass.simpleName}{responseType=$responseType, rawChatCompletion=$rawChatCompletion}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParams.kt new file mode 100644 index 000000000..73741b581 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParams.kt @@ -0,0 +1,765 @@ +package com.openai.models.chat.completions + +import com.openai.core.JsonField +import com.openai.core.JsonSchemaLocalValidation +import com.openai.core.JsonValue +import com.openai.core.checkRequired +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.responseFormatFromClass +import com.openai.models.ChatModel +import com.openai.models.ReasoningEffort +import java.util.Objects +import java.util.Optional + +/** + * A wrapper for [ChatCompletionCreateParams] that provides a type-safe [Builder] that can record + * the [responseType] used to derive a JSON schema from an arbitrary class when using the + * _Structured Outputs_ feature. When a JSON response is received, it is deserialized to am instance + * of that type. See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class that will be used to derive the JSON schema in the request and to + * which the JSON response will be deserialized. + */ +class StructuredChatCompletionCreateParams +internal constructor( + @get:JvmName("responseType") val responseType: Class, + /** + * The raw, underlying chat completion create parameters wrapped by this structured instance of + * the parameters. + */ + @get:JvmName("rawParams") val rawParams: ChatCompletionCreateParams, +) { + + companion object { + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + private var responseType: Class? = null + private var paramsBuilder = ChatCompletionCreateParams.builder() + + @JvmSynthetic + internal fun wrap( + responseType: Class, + paramsBuilder: ChatCompletionCreateParams.Builder, + localValidation: JsonSchemaLocalValidation, + ) = apply { + this.responseType = responseType + this.paramsBuilder = paramsBuilder + // Convert the class to a JSON schema and apply it to the delegate `Builder`. + responseFormat(responseType, localValidation) + } + + /** Injects a given `ChatCompletionCreateParams.Builder`. For use only when testing. */ + @JvmSynthetic + internal fun inject(paramsBuilder: ChatCompletionCreateParams.Builder) = apply { + this.paramsBuilder = paramsBuilder + } + + /** @see ChatCompletionCreateParams.Builder.body */ + fun body(body: ChatCompletionCreateParams.Body) = apply { paramsBuilder.body(body) } + + /** @see ChatCompletionCreateParams.Builder.messages */ + fun messages(messages: List) = apply { + paramsBuilder.messages(messages) + } + + /** @see ChatCompletionCreateParams.Builder.messages */ + fun messages(messages: JsonField>) = apply { + paramsBuilder.messages(messages) + } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(message: ChatCompletionMessageParam) = apply { + paramsBuilder.addMessage(message) + } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(developer: ChatCompletionDeveloperMessageParam) = apply { + paramsBuilder.addMessage(developer) + } + + /** @see ChatCompletionCreateParams.Builder.addDeveloperMessage */ + fun addDeveloperMessage(content: ChatCompletionDeveloperMessageParam.Content) = apply { + paramsBuilder.addDeveloperMessage(content) + } + + /** @see ChatCompletionCreateParams.Builder.addDeveloperMessage */ + fun addDeveloperMessage(text: String) = apply { paramsBuilder.addDeveloperMessage(text) } + + /** @see ChatCompletionCreateParams.Builder.addDeveloperMessageOfArrayOfContentParts */ + fun addDeveloperMessageOfArrayOfContentParts( + arrayOfContentParts: List + ) = apply { paramsBuilder.addDeveloperMessageOfArrayOfContentParts(arrayOfContentParts) } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(system: ChatCompletionSystemMessageParam) = apply { + paramsBuilder.addMessage(system) + } + + /** @see ChatCompletionCreateParams.Builder.addSystemMessage */ + fun addSystemMessage(content: ChatCompletionSystemMessageParam.Content) = apply { + paramsBuilder.addSystemMessage(content) + } + + /** @see ChatCompletionCreateParams.Builder.addSystemMessage */ + fun addSystemMessage(text: String) = apply { paramsBuilder.addSystemMessage(text) } + + /** @see ChatCompletionCreateParams.Builder.addSystemMessageOfArrayOfContentParts */ + fun addSystemMessageOfArrayOfContentParts( + arrayOfContentParts: List + ) = apply { paramsBuilder.addSystemMessageOfArrayOfContentParts(arrayOfContentParts) } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(user: ChatCompletionUserMessageParam) = apply { + paramsBuilder.addMessage(user) + } + + /** @see ChatCompletionCreateParams.Builder.addUserMessage */ + fun addUserMessage(content: ChatCompletionUserMessageParam.Content) = apply { + paramsBuilder.addUserMessage(content) + } + + /** @see ChatCompletionCreateParams.Builder.addUserMessage */ + fun addUserMessage(text: String) = apply { paramsBuilder.addUserMessage(text) } + + /** @see ChatCompletionCreateParams.Builder.addUserMessageOfArrayOfContentParts */ + fun addUserMessageOfArrayOfContentParts( + arrayOfContentParts: List + ) = apply { paramsBuilder.addUserMessageOfArrayOfContentParts(arrayOfContentParts) } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(assistant: ChatCompletionAssistantMessageParam) = apply { + paramsBuilder.addMessage(assistant) + } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(assistant: ChatCompletionMessage) = apply { + paramsBuilder.addMessage(assistant) + } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + fun addMessage(tool: ChatCompletionToolMessageParam) = apply { + paramsBuilder.addMessage(tool) + } + + /** @see ChatCompletionCreateParams.Builder.addMessage */ + @Deprecated("deprecated") + fun addMessage(function: ChatCompletionFunctionMessageParam) = apply { + paramsBuilder.addMessage(function) + } + + /** @see ChatCompletionCreateParams.Builder.model */ + fun model(model: ChatModel) = apply { paramsBuilder.model(model) } + + /** @see ChatCompletionCreateParams.Builder.model */ + fun model(model: JsonField) = apply { paramsBuilder.model(model) } + + /** @see ChatCompletionCreateParams.Builder.model */ + fun model(value: String) = apply { paramsBuilder.model(value) } + + /** @see ChatCompletionCreateParams.Builder.audio */ + fun audio(audio: ChatCompletionAudioParam?) = apply { paramsBuilder.audio(audio) } + + /** @see ChatCompletionCreateParams.Builder.audio */ + fun audio(audio: Optional) = apply { paramsBuilder.audio(audio) } + + /** @see ChatCompletionCreateParams.Builder.audio */ + fun audio(audio: JsonField) = apply { paramsBuilder.audio(audio) } + + /** @see ChatCompletionCreateParams.Builder.frequencyPenalty */ + fun frequencyPenalty(frequencyPenalty: Double?) = apply { + paramsBuilder.frequencyPenalty(frequencyPenalty) + } + + /** @see ChatCompletionCreateParams.Builder.frequencyPenalty */ + fun frequencyPenalty(frequencyPenalty: Double) = apply { + paramsBuilder.frequencyPenalty(frequencyPenalty) + } + + /** @see ChatCompletionCreateParams.Builder.frequencyPenalty */ + fun frequencyPenalty(frequencyPenalty: Optional) = apply { + paramsBuilder.frequencyPenalty(frequencyPenalty) + } + + /** @see ChatCompletionCreateParams.Builder.frequencyPenalty */ + fun frequencyPenalty(frequencyPenalty: JsonField) = apply { + paramsBuilder.frequencyPenalty(frequencyPenalty) + } + + /** @see ChatCompletionCreateParams.Builder.functionCall */ + @Deprecated("deprecated") + fun functionCall(functionCall: ChatCompletionCreateParams.FunctionCall) = apply { + paramsBuilder.functionCall(functionCall) + } + + /** @see ChatCompletionCreateParams.Builder.functionCall */ + @Deprecated("deprecated") + fun functionCall(functionCall: JsonField) = apply { + paramsBuilder.functionCall(functionCall) + } + + /** @see ChatCompletionCreateParams.Builder.functionCall */ + @Deprecated("deprecated") + fun functionCall(mode: ChatCompletionCreateParams.FunctionCall.FunctionCallMode) = apply { + paramsBuilder.functionCall(mode) + } + + /** @see ChatCompletionCreateParams.Builder.functionCall */ + @Deprecated("deprecated") + fun functionCall(functionCallOption: ChatCompletionFunctionCallOption) = apply { + paramsBuilder.functionCall(functionCallOption) + } + + /** @see ChatCompletionCreateParams.Builder.functions */ + @Deprecated("deprecated") + fun functions(functions: List) = apply { + paramsBuilder.functions(functions) + } + + /** @see ChatCompletionCreateParams.Builder.functions */ + @Deprecated("deprecated") + fun functions(functions: JsonField>) = apply { + paramsBuilder.functions(functions) + } + + /** @see ChatCompletionCreateParams.Builder.addFunction */ + @Deprecated("deprecated") + fun addFunction(function: ChatCompletionCreateParams.Function) = apply { + paramsBuilder.addFunction(function) + } + + /** @see ChatCompletionCreateParams.Builder.logitBias */ + fun logitBias(logitBias: ChatCompletionCreateParams.LogitBias?) = apply { + paramsBuilder.logitBias(logitBias) + } + + /** @see ChatCompletionCreateParams.Builder.logitBias */ + fun logitBias(logitBias: Optional) = apply { + paramsBuilder.logitBias(logitBias) + } + + /** @see ChatCompletionCreateParams.Builder.logitBias */ + fun logitBias(logitBias: JsonField) = apply { + paramsBuilder.logitBias(logitBias) + } + + /** @see ChatCompletionCreateParams.Builder.logprobs */ + fun logprobs(logprobs: Boolean?) = apply { paramsBuilder.logprobs(logprobs) } + + /** @see ChatCompletionCreateParams.Builder.logprobs */ + fun logprobs(logprobs: Boolean) = apply { paramsBuilder.logprobs(logprobs) } + + /** @see ChatCompletionCreateParams.Builder.logprobs */ + fun logprobs(logprobs: Optional) = apply { paramsBuilder.logprobs(logprobs) } + + /** @see ChatCompletionCreateParams.Builder.logprobs */ + fun logprobs(logprobs: JsonField) = apply { paramsBuilder.logprobs(logprobs) } + + /** @see ChatCompletionCreateParams.Builder.maxCompletionTokens */ + fun maxCompletionTokens(maxCompletionTokens: Long?) = apply { + paramsBuilder.maxCompletionTokens(maxCompletionTokens) + } + + /** @see ChatCompletionCreateParams.Builder.maxCompletionTokens */ + fun maxCompletionTokens(maxCompletionTokens: Long) = apply { + paramsBuilder.maxCompletionTokens(maxCompletionTokens) + } + + /** @see ChatCompletionCreateParams.Builder.maxCompletionTokens */ + fun maxCompletionTokens(maxCompletionTokens: Optional) = apply { + paramsBuilder.maxCompletionTokens(maxCompletionTokens) + } + + /** @see ChatCompletionCreateParams.Builder.maxCompletionTokens */ + fun maxCompletionTokens(maxCompletionTokens: JsonField) = apply { + paramsBuilder.maxCompletionTokens(maxCompletionTokens) + } + + /** @see ChatCompletionCreateParams.Builder.maxTokens */ + @Deprecated("deprecated") + fun maxTokens(maxTokens: Long?) = apply { paramsBuilder.maxTokens(maxTokens) } + + /** @see ChatCompletionCreateParams.Builder.maxTokens */ + @Deprecated("deprecated") + fun maxTokens(maxTokens: Long) = apply { paramsBuilder.maxTokens(maxTokens) } + + /** @see ChatCompletionCreateParams.Builder.maxTokens */ + @Deprecated("deprecated") + fun maxTokens(maxTokens: Optional) = apply { paramsBuilder.maxTokens(maxTokens) } + + /** @see ChatCompletionCreateParams.Builder.maxTokens */ + @Deprecated("deprecated") + fun maxTokens(maxTokens: JsonField) = apply { paramsBuilder.maxTokens(maxTokens) } + + /** @see ChatCompletionCreateParams.Builder.metadata */ + fun metadata(metadata: ChatCompletionCreateParams.Metadata?) = apply { + paramsBuilder.metadata(metadata) + } + + /** @see ChatCompletionCreateParams.Builder.metadata */ + fun metadata(metadata: Optional) = apply { + paramsBuilder.metadata(metadata) + } + + /** @see ChatCompletionCreateParams.Builder.metadata */ + fun metadata(metadata: JsonField) = apply { + paramsBuilder.metadata(metadata) + } + + /** @see ChatCompletionCreateParams.Builder.modalities */ + fun modalities(modalities: List?) = apply { + paramsBuilder.modalities(modalities) + } + + /** @see ChatCompletionCreateParams.Builder.modalities */ + fun modalities(modalities: Optional>) = apply { + paramsBuilder.modalities(modalities) + } + + /** @see ChatCompletionCreateParams.Builder.modalities */ + fun modalities(modalities: JsonField>) = apply { + paramsBuilder.modalities(modalities) + } + + /** @see ChatCompletionCreateParams.Builder.addModality */ + fun addModality(modality: ChatCompletionCreateParams.Modality) = apply { + paramsBuilder.addModality(modality) + } + + /** @see ChatCompletionCreateParams.Builder.n */ + fun n(n: Long?) = apply { paramsBuilder.n(n) } + + /** @see ChatCompletionCreateParams.Builder.n */ + fun n(n: Long) = apply { paramsBuilder.n(n) } + + /** @see ChatCompletionCreateParams.Builder.n */ + fun n(n: Optional) = apply { paramsBuilder.n(n) } + + /** @see ChatCompletionCreateParams.Builder.n */ + fun n(n: JsonField) = apply { paramsBuilder.n(n) } + + /** @see ChatCompletionCreateParams.Builder.parallelToolCalls */ + fun parallelToolCalls(parallelToolCalls: Boolean) = apply { + paramsBuilder.parallelToolCalls(parallelToolCalls) + } + + /** @see ChatCompletionCreateParams.Builder.parallelToolCalls */ + fun parallelToolCalls(parallelToolCalls: JsonField) = apply { + paramsBuilder.parallelToolCalls(parallelToolCalls) + } + + /** @see ChatCompletionCreateParams.Builder.prediction */ + fun prediction(prediction: ChatCompletionPredictionContent?) = apply { + paramsBuilder.prediction(prediction) + } + + /** @see ChatCompletionCreateParams.Builder.prediction */ + fun prediction(prediction: Optional) = apply { + paramsBuilder.prediction(prediction) + } + + /** @see ChatCompletionCreateParams.Builder.prediction */ + fun prediction(prediction: JsonField) = apply { + paramsBuilder.prediction(prediction) + } + + /** @see ChatCompletionCreateParams.Builder.presencePenalty */ + fun presencePenalty(presencePenalty: Double?) = apply { + paramsBuilder.presencePenalty(presencePenalty) + } + + /** @see ChatCompletionCreateParams.Builder.presencePenalty */ + fun presencePenalty(presencePenalty: Double) = apply { + paramsBuilder.presencePenalty(presencePenalty) + } + + /** @see ChatCompletionCreateParams.Builder.presencePenalty */ + fun presencePenalty(presencePenalty: Optional) = apply { + paramsBuilder.presencePenalty(presencePenalty) + } + + /** @see ChatCompletionCreateParams.Builder.presencePenalty */ + fun presencePenalty(presencePenalty: JsonField) = apply { + paramsBuilder.presencePenalty(presencePenalty) + } + + /** @see ChatCompletionCreateParams.Builder.reasoningEffort */ + fun reasoningEffort(reasoningEffort: ReasoningEffort?) = apply { + paramsBuilder.reasoningEffort(reasoningEffort) + } + + /** @see ChatCompletionCreateParams.Builder.reasoningEffort */ + fun reasoningEffort(reasoningEffort: Optional) = apply { + paramsBuilder.reasoningEffort(reasoningEffort) + } + + /** @see ChatCompletionCreateParams.Builder.reasoningEffort */ + fun reasoningEffort(reasoningEffort: JsonField) = apply { + paramsBuilder.reasoningEffort(reasoningEffort) + } + + /** + * Sets the response format to a JSON schema derived from the structure of the given class. + * + * @see ChatCompletionCreateParams.Builder.responseFormat + */ + @JvmOverloads + fun responseFormat( + responseType: Class, + localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES, + ) = apply { + this.responseType = responseType + paramsBuilder.responseFormat(responseFormatFromClass(responseType, localValidation)) + } + + /** @see ChatCompletionCreateParams.Builder.seed */ + fun seed(seed: Long?) = apply { paramsBuilder.seed(seed) } + + /** @see ChatCompletionCreateParams.Builder.seed */ + fun seed(seed: Long) = apply { paramsBuilder.seed(seed) } + + /** @see ChatCompletionCreateParams.Builder.seed */ + fun seed(seed: Optional) = apply { paramsBuilder.seed(seed) } + + /** @see ChatCompletionCreateParams.Builder.seed */ + fun seed(seed: JsonField) = apply { paramsBuilder.seed(seed) } + + /** @see ChatCompletionCreateParams.Builder.serviceTier */ + fun serviceTier(serviceTier: ChatCompletionCreateParams.ServiceTier?) = apply { + paramsBuilder.serviceTier(serviceTier) + } + + /** @see ChatCompletionCreateParams.Builder.serviceTier */ + fun serviceTier(serviceTier: Optional) = apply { + paramsBuilder.serviceTier(serviceTier) + } + + /** @see ChatCompletionCreateParams.Builder.serviceTier */ + fun serviceTier(serviceTier: JsonField) = apply { + paramsBuilder.serviceTier(serviceTier) + } + + /** @see ChatCompletionCreateParams.Builder.stop */ + fun stop(stop: ChatCompletionCreateParams.Stop?) = apply { paramsBuilder.stop(stop) } + + /** @see ChatCompletionCreateParams.Builder.stop */ + fun stop(stop: Optional) = apply { + paramsBuilder.stop(stop) + } + + /** @see ChatCompletionCreateParams.Builder.stop */ + fun stop(stop: JsonField) = apply { + paramsBuilder.stop(stop) + } + + /** @see ChatCompletionCreateParams.Builder.stop */ + fun stop(string: String) = apply { paramsBuilder.stop(string) } + + /** @see ChatCompletionCreateParams.Builder.stopOfStrings */ + fun stopOfStrings(strings: List) = apply { paramsBuilder.stopOfStrings(strings) } + + /** @see ChatCompletionCreateParams.Builder.store */ + fun store(store: Boolean?) = apply { paramsBuilder.store(store) } + + /** @see ChatCompletionCreateParams.Builder.store */ + fun store(store: Boolean) = apply { paramsBuilder.store(store) } + + /** @see ChatCompletionCreateParams.Builder.store */ + fun store(store: Optional) = apply { paramsBuilder.store(store) } + + /** @see ChatCompletionCreateParams.Builder.store */ + fun store(store: JsonField) = apply { paramsBuilder.store(store) } + + /** @see ChatCompletionCreateParams.Builder.streamOptions */ + fun streamOptions(streamOptions: ChatCompletionStreamOptions?) = apply { + paramsBuilder.streamOptions(streamOptions) + } + + /** @see ChatCompletionCreateParams.Builder.streamOptions */ + fun streamOptions(streamOptions: Optional) = apply { + paramsBuilder.streamOptions(streamOptions) + } + + /** @see ChatCompletionCreateParams.Builder.streamOptions */ + fun streamOptions(streamOptions: JsonField) = apply { + paramsBuilder.streamOptions(streamOptions) + } + + /** @see ChatCompletionCreateParams.Builder.temperature */ + fun temperature(temperature: Double?) = apply { paramsBuilder.temperature(temperature) } + + /** @see ChatCompletionCreateParams.Builder.temperature */ + fun temperature(temperature: Double) = apply { paramsBuilder.temperature(temperature) } + + /** @see ChatCompletionCreateParams.Builder.temperature */ + fun temperature(temperature: Optional) = apply { + paramsBuilder.temperature(temperature) + } + + /** @see ChatCompletionCreateParams.Builder.temperature */ + fun temperature(temperature: JsonField) = apply { + paramsBuilder.temperature(temperature) + } + + /** @see ChatCompletionCreateParams.Builder.toolChoice */ + fun toolChoice(toolChoice: ChatCompletionToolChoiceOption) = apply { + paramsBuilder.toolChoice(toolChoice) + } + + /** @see ChatCompletionCreateParams.Builder.toolChoice */ + fun toolChoice(toolChoice: JsonField) = apply { + paramsBuilder.toolChoice(toolChoice) + } + + /** @see ChatCompletionCreateParams.Builder.toolChoice */ + fun toolChoice(auto: ChatCompletionToolChoiceOption.Auto) = apply { + paramsBuilder.toolChoice(auto) + } + + /** @see ChatCompletionCreateParams.Builder.toolChoice */ + fun toolChoice(namedToolChoice: ChatCompletionNamedToolChoice) = apply { + paramsBuilder.toolChoice(namedToolChoice) + } + + /** @see ChatCompletionCreateParams.Builder.tools */ + fun tools(tools: List) = apply { paramsBuilder.tools(tools) } + + /** @see ChatCompletionCreateParams.Builder.tools */ + fun tools(tools: JsonField>) = apply { paramsBuilder.tools(tools) } + + /** @see ChatCompletionCreateParams.Builder.addTool */ + fun addTool(tool: ChatCompletionTool) = apply { paramsBuilder.addTool(tool) } + + /** @see ChatCompletionCreateParams.Builder.topLogprobs */ + fun topLogprobs(topLogprobs: Long?) = apply { paramsBuilder.topLogprobs(topLogprobs) } + + /** @see ChatCompletionCreateParams.Builder.topLogprobs */ + fun topLogprobs(topLogprobs: Long) = apply { paramsBuilder.topLogprobs(topLogprobs) } + + /** @see ChatCompletionCreateParams.Builder.topLogprobs */ + fun topLogprobs(topLogprobs: Optional) = apply { + paramsBuilder.topLogprobs(topLogprobs) + } + + /** @see ChatCompletionCreateParams.Builder.topLogprobs */ + fun topLogprobs(topLogprobs: JsonField) = apply { + paramsBuilder.topLogprobs(topLogprobs) + } + + /** @see ChatCompletionCreateParams.Builder.topP */ + fun topP(topP: Double?) = apply { paramsBuilder.topP(topP) } + + /** @see ChatCompletionCreateParams.Builder.topP */ + fun topP(topP: Double) = apply { paramsBuilder.topP(topP) } + + /** @see ChatCompletionCreateParams.Builder.topP */ + fun topP(topP: Optional) = apply { paramsBuilder.topP(topP) } + + /** @see ChatCompletionCreateParams.Builder.topP */ + fun topP(topP: JsonField) = apply { paramsBuilder.topP(topP) } + + /** @see ChatCompletionCreateParams.Builder.user */ + fun user(user: String) = apply { paramsBuilder.user(user) } + + /** @see ChatCompletionCreateParams.Builder.user */ + fun user(user: JsonField) = apply { paramsBuilder.user(user) } + + /** @see ChatCompletionCreateParams.Builder.webSearchOptions */ + fun webSearchOptions(webSearchOptions: ChatCompletionCreateParams.WebSearchOptions) = + apply { + paramsBuilder.webSearchOptions(webSearchOptions) + } + + /** @see ChatCompletionCreateParams.Builder.webSearchOptions */ + fun webSearchOptions( + webSearchOptions: JsonField + ) = apply { paramsBuilder.webSearchOptions(webSearchOptions) } + + /** @see ChatCompletionCreateParams.Builder.additionalBodyProperties */ + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + paramsBuilder.additionalBodyProperties(additionalBodyProperties) + } + + /** @see ChatCompletionCreateParams.Builder.putAdditionalBodyProperty */ + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + paramsBuilder.putAdditionalBodyProperty(key, value) + } + + /** @see ChatCompletionCreateParams.Builder.putAllAdditionalBodyProperties */ + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + paramsBuilder.putAllAdditionalBodyProperties(additionalBodyProperties) + } + + /** @see ChatCompletionCreateParams.Builder.removeAdditionalBodyProperty */ + fun removeAdditionalBodyProperty(key: String) = apply { + paramsBuilder.removeAdditionalBodyProperty(key) + } + + /** @see ChatCompletionCreateParams.Builder.removeAllAdditionalBodyProperties */ + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + paramsBuilder.removeAllAdditionalBodyProperties(keys) + } + + /** @see ChatCompletionCreateParams.Builder.additionalHeaders */ + fun additionalHeaders(additionalHeaders: Headers) = apply { + paramsBuilder.additionalHeaders(additionalHeaders) + } + + /** @see ChatCompletionCreateParams.Builder.additionalHeaders */ + fun additionalHeaders(additionalHeaders: Map>) = apply { + paramsBuilder.additionalHeaders(additionalHeaders) + } + + /** @see ChatCompletionCreateParams.Builder.putAdditionalHeader */ + fun putAdditionalHeader(name: String, value: String) = apply { + paramsBuilder.putAdditionalHeader(name, value) + } + + /** @see ChatCompletionCreateParams.Builder.putAdditionalHeaders */ + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + paramsBuilder.putAdditionalHeaders(name, values) + } + + /** @see ChatCompletionCreateParams.Builder.putAllAdditionalHeaders */ + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + paramsBuilder.putAllAdditionalHeaders(additionalHeaders) + } + + /** @see ChatCompletionCreateParams.Builder.putAllAdditionalHeaders */ + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + paramsBuilder.putAllAdditionalHeaders(additionalHeaders) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAdditionalHeaders */ + fun replaceAdditionalHeaders(name: String, value: String) = apply { + paramsBuilder.replaceAdditionalHeaders(name, value) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAdditionalHeaders */ + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + paramsBuilder.replaceAdditionalHeaders(name, values) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAllAdditionalHeaders */ + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + paramsBuilder.replaceAllAdditionalHeaders(additionalHeaders) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAllAdditionalHeaders */ + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + paramsBuilder.replaceAllAdditionalHeaders(additionalHeaders) + } + + /** @see ChatCompletionCreateParams.Builder.removeAdditionalHeaders */ + fun removeAdditionalHeaders(name: String) = apply { + paramsBuilder.removeAdditionalHeaders(name) + } + + /** @see ChatCompletionCreateParams.Builder.removeAllAdditionalHeaders */ + fun removeAllAdditionalHeaders(names: Set) = apply { + paramsBuilder.removeAllAdditionalHeaders(names) + } + + /** @see ChatCompletionCreateParams.Builder.additionalQueryParams */ + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + paramsBuilder.additionalQueryParams(additionalQueryParams) + } + + /** @see ChatCompletionCreateParams.Builder.additionalQueryParams */ + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + paramsBuilder.additionalQueryParams(additionalQueryParams) + } + + /** @see ChatCompletionCreateParams.Builder.putAdditionalQueryParam */ + fun putAdditionalQueryParam(key: String, value: String) = apply { + paramsBuilder.putAdditionalQueryParam(key, value) + } + + /** @see ChatCompletionCreateParams.Builder.putAdditionalQueryParams */ + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + paramsBuilder.putAdditionalQueryParams(key, values) + } + + /** @see ChatCompletionCreateParams.Builder.putAllAdditionalQueryParams */ + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + paramsBuilder.putAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ChatCompletionCreateParams.Builder.putAllAdditionalQueryParams */ + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + paramsBuilder.putAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAdditionalQueryParams */ + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + paramsBuilder.replaceAdditionalQueryParams(key, value) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAdditionalQueryParams */ + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + paramsBuilder.replaceAdditionalQueryParams(key, values) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAllAdditionalQueryParams */ + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + paramsBuilder.replaceAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ChatCompletionCreateParams.Builder.replaceAllAdditionalQueryParams */ + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + paramsBuilder.replaceAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ChatCompletionCreateParams.Builder.removeAdditionalQueryParams */ + fun removeAdditionalQueryParams(key: String) = apply { + paramsBuilder.removeAdditionalQueryParams(key) + } + + /** @see ChatCompletionCreateParams.Builder.removeAllAdditionalQueryParams */ + fun removeAllAdditionalQueryParams(keys: Set) = apply { + paramsBuilder.removeAllAdditionalQueryParams(keys) + } + + /** + * Returns an immutable instance of [StructuredChatCompletionCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .messages() + * .model() + * .responseFormat() + * ``` + * + * @throws IllegalStateException If any required field is unset. + */ + fun build() = + StructuredChatCompletionCreateParams( + checkRequired("responseType", responseType), + paramsBuilder.build(), + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StructuredChatCompletionCreateParams<*> && + responseType == other.responseType && + rawParams == other.rawParams + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawParams) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "${javaClass.simpleName}{responseType=$responseType, rawParams=$rawParams}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessage.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessage.kt new file mode 100644 index 000000000..27e8a3c74 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessage.kt @@ -0,0 +1,95 @@ +package com.openai.models.chat.completions + +import com.openai.core.JsonField +import com.openai.core.JsonValue +import com.openai.core.responseTypeFromJson +import com.openai.models.chat.completions.ChatCompletionMessage.FunctionCall +import java.util.Objects +import java.util.Optional + +/** + * A wrapper for [ChatCompletionMessage] that provides type-safe access to the [content] when using + * the _Structured Outputs_ feature to deserialize a JSON response to an instance of an arbitrary + * class. See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class to which the JSON data in the content will be deserialized when + * [content] is called. + */ +class StructuredChatCompletionMessage +internal constructor( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawMessage") val rawMessage: ChatCompletionMessage, +) { + + private val content: JsonField by lazy { + rawMessage._content().map { responseTypeFromJson(it, responseType) } + } + + /** @see ChatCompletionMessage.content */ + fun content(): Optional = content.getOptional("content") + + /** @see ChatCompletionMessage.refusal */ + fun refusal(): Optional = rawMessage.refusal() + + /** @see ChatCompletionMessage._role */ + fun _role(): JsonValue = rawMessage._role() + + /** @see ChatCompletionMessage.annotations */ + fun annotations(): Optional> = rawMessage.annotations() + + /** @see ChatCompletionMessage.audio */ + fun audio(): Optional = rawMessage.audio() + + /** @see ChatCompletionMessage.functionCall */ + @Deprecated("deprecated") fun functionCall(): Optional = rawMessage.functionCall() + + /** @see ChatCompletionMessage.toolCalls */ + fun toolCalls(): Optional> = rawMessage.toolCalls() + + /** @see ChatCompletionMessage._content */ + fun _content(): JsonField = content + + /** @see ChatCompletionMessage._refusal */ + fun _refusal(): JsonField = rawMessage._refusal() + + /** @see ChatCompletionMessage._annotations */ + fun _annotations(): JsonField> = + rawMessage._annotations() + + /** @see ChatCompletionMessage._audio */ + fun _audio(): JsonField = rawMessage._audio() + + /** @see ChatCompletionMessage._functionCall */ + @Deprecated("deprecated") + fun _functionCall(): JsonField = rawMessage._functionCall() + + /** @see ChatCompletionMessage._toolCalls */ + fun _toolCalls(): JsonField> = rawMessage._toolCalls() + + /** @see ChatCompletionMessage._additionalProperties */ + fun _additionalProperties(): Map = rawMessage._additionalProperties() + + /** @see ChatCompletionMessage.validate */ + // `content()` is not included in the validation by the delegate method, so just call it. + fun validate(): ChatCompletionMessage = rawMessage.validate() + + /** @see ChatCompletionMessage.isValid */ + fun isValid(): Boolean = rawMessage.isValid() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StructuredChatCompletionMessage<*> && + responseType == other.responseType && + rawMessage == other.rawMessage + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawMessage) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "${javaClass.simpleName}{responseType=$responseType, rawMessage=$rawMessage}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPage.kt index 4088b3eff..bc6f6aa63 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPage.kt @@ -2,13 +2,13 @@ package com.openai.models.chat.completions.messages +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.models.chat.completions.ChatCompletionStoreMessage import com.openai.services.blocking.chat.completions.MessageService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [MessageService.list] */ @@ -17,7 +17,7 @@ private constructor( private val service: MessageService, private val params: MessageListParams, private val response: MessageListPageResponse, -) { +) : Page { /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. @@ -34,19 +34,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): MessageListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): MessageListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): MessageListParams = params @@ -115,25 +112,6 @@ private constructor( ) } - class AutoPager(private val firstPage: MessageListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPageAsync.kt index d013eff23..7baa95a6f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListPageAsync.kt @@ -2,6 +2,8 @@ package com.openai.models.chat.completions.messages +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.models.chat.completions.ChatCompletionStoreMessage import com.openai.services.async.chat.completions.MessageServiceAsync @@ -9,16 +11,16 @@ import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [MessageServiceAsync.list] */ class MessageListPageAsync private constructor( private val service: MessageServiceAsync, + private val streamHandlerExecutor: Executor, private val params: MessageListParams, private val response: MessageListPageResponse, -) { +) : PageAsync { /** * Delegates to [MessageListPageResponse], but gracefully handles missing data. @@ -35,22 +37,18 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): MessageListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): MessageListParams = params @@ -68,6 +66,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -79,18 +78,24 @@ private constructor( class Builder internal constructor() { private var service: MessageServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: MessageListParams? = null private var response: MessageListPageResponse? = null @JvmSynthetic internal fun from(messageListPageAsync: MessageListPageAsync) = apply { service = messageListPageAsync.service + streamHandlerExecutor = messageListPageAsync.streamHandlerExecutor params = messageListPageAsync.params response = messageListPageAsync.response } fun service(service: MessageServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: MessageListParams) = apply { this.params = params } @@ -105,6 +110,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -114,50 +120,22 @@ private constructor( fun build(): MessageListPageAsync = MessageListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: MessageListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (ChatCompletionStoreMessage) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is MessageListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is MessageListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "MessageListPageAsync{service=$service, params=$params, response=$response}" + "MessageListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListParams.kt index 0f7c3f25f..a60bc6d6e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/chat/completions/messages/MessageListParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.errors.OpenAIInvalidDataException @@ -20,7 +19,7 @@ import kotlin.jvm.optionals.getOrNull */ class MessageListParams private constructor( - private val completionId: String, + private val completionId: String?, private val after: String?, private val limit: Long?, private val order: Order?, @@ -28,7 +27,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun completionId(): String = completionId + fun completionId(): Optional = Optional.ofNullable(completionId) /** Identifier for the last message from the previous pagination request. */ fun after(): Optional = Optional.ofNullable(after) @@ -50,14 +49,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [MessageListParams]. - * - * The following fields are required: - * ```java - * .completionId() - * ``` - */ + @JvmStatic fun none(): MessageListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [MessageListParams]. */ @JvmStatic fun builder() = Builder() } @@ -81,7 +75,10 @@ private constructor( additionalQueryParams = messageListParams.additionalQueryParams.toBuilder() } - fun completionId(completionId: String) = apply { this.completionId = completionId } + fun completionId(completionId: String?) = apply { this.completionId = completionId } + + /** Alias for calling [Builder.completionId] with `completionId.orElse(null)`. */ + fun completionId(completionId: Optional) = completionId(completionId.getOrNull()) /** Identifier for the last message from the previous pagination request. */ fun after(after: String?) = apply { this.after = after } @@ -213,17 +210,10 @@ private constructor( * Returns an immutable instance of [MessageListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .completionId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): MessageListParams = MessageListParams( - checkRequired("completionId", completionId), + completionId, after, limit, order, @@ -234,7 +224,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> completionId + 0 -> completionId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateParams.kt index 08525daa0..34c286275 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateParams.kt @@ -29,6 +29,10 @@ import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader import com.openai.models.responses.ResponseInputText import java.util.Collections import java.util.Objects @@ -196,8 +200,13 @@ private constructor( body.customDataSourceConfig(itemSchema) } - /** Alias for calling [dataSourceConfig] with `DataSourceConfig.ofLogs(logs)`. */ - fun dataSourceConfig(logs: DataSourceConfig.Logs) = apply { body.dataSourceConfig(logs) } + /** + * Alias for calling [dataSourceConfig] with + * `DataSourceConfig.ofStoredCompletions(storedCompletions)`. + */ + fun dataSourceConfig(storedCompletions: DataSourceConfig.StoredCompletions) = apply { + body.dataSourceConfig(storedCompletions) + } /** A list of graders for all eval runs in this group. */ fun testingCriteria(testingCriteria: List) = apply { @@ -235,7 +244,7 @@ private constructor( * Alias for calling [addTestingCriterion] with * `TestingCriterion.ofStringCheck(stringCheck)`. */ - fun addTestingCriterion(stringCheck: EvalStringCheckGrader) = apply { + fun addTestingCriterion(stringCheck: StringCheckGrader) = apply { body.addTestingCriterion(stringCheck) } @@ -243,7 +252,7 @@ private constructor( * Alias for calling [addTestingCriterion] with * `TestingCriterion.ofTextSimilarity(textSimilarity)`. */ - fun addTestingCriterion(textSimilarity: EvalTextSimilarityGrader) = apply { + fun addTestingCriterion(textSimilarity: TestingCriterion.TextSimilarity) = apply { body.addTestingCriterion(textSimilarity) } @@ -602,9 +611,12 @@ private constructor( fun customDataSourceConfig(itemSchema: DataSourceConfig.Custom.ItemSchema) = dataSourceConfig(DataSourceConfig.Custom.builder().itemSchema(itemSchema).build()) - /** Alias for calling [dataSourceConfig] with `DataSourceConfig.ofLogs(logs)`. */ - fun dataSourceConfig(logs: DataSourceConfig.Logs) = - dataSourceConfig(DataSourceConfig.ofLogs(logs)) + /** + * Alias for calling [dataSourceConfig] with + * `DataSourceConfig.ofStoredCompletions(storedCompletions)`. + */ + fun dataSourceConfig(storedCompletions: DataSourceConfig.StoredCompletions) = + dataSourceConfig(DataSourceConfig.ofStoredCompletions(storedCompletions)) /** A list of graders for all eval runs in this group. */ fun testingCriteria(testingCriteria: List) = @@ -644,14 +656,14 @@ private constructor( * Alias for calling [addTestingCriterion] with * `TestingCriterion.ofStringCheck(stringCheck)`. */ - fun addTestingCriterion(stringCheck: EvalStringCheckGrader) = + fun addTestingCriterion(stringCheck: StringCheckGrader) = addTestingCriterion(TestingCriterion.ofStringCheck(stringCheck)) /** * Alias for calling [addTestingCriterion] with * `TestingCriterion.ofTextSimilarity(textSimilarity)`. */ - fun addTestingCriterion(textSimilarity: EvalTextSimilarityGrader) = + fun addTestingCriterion(textSimilarity: TestingCriterion.TextSimilarity) = addTestingCriterion(TestingCriterion.ofTextSimilarity(textSimilarity)) /** Alias for calling [addTestingCriterion] with `TestingCriterion.ofPython(python)`. */ @@ -800,7 +812,7 @@ private constructor( class DataSourceConfig private constructor( private val custom: Custom? = null, - private val logs: Logs? = null, + private val storedCompletions: StoredCompletions? = null, private val _json: JsonValue? = null, ) { @@ -816,11 +828,12 @@ private constructor( * A data source config which specifies the metadata property of your stored completions * query. This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. */ - fun logs(): Optional = Optional.ofNullable(logs) + fun storedCompletions(): Optional = + Optional.ofNullable(storedCompletions) fun isCustom(): Boolean = custom != null - fun isLogs(): Boolean = logs != null + fun isStoredCompletions(): Boolean = storedCompletions != null /** * A CustomDataSourceConfig object that defines the schema for the data source used for the @@ -834,14 +847,15 @@ private constructor( * A data source config which specifies the metadata property of your stored completions * query. This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. */ - fun asLogs(): Logs = logs.getOrThrow("logs") + fun asStoredCompletions(): StoredCompletions = + storedCompletions.getOrThrow("storedCompletions") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { custom != null -> visitor.visitCustom(custom) - logs != null -> visitor.visitLogs(logs) + storedCompletions != null -> visitor.visitStoredCompletions(storedCompletions) else -> visitor.unknown(_json) } @@ -858,8 +872,8 @@ private constructor( custom.validate() } - override fun visitLogs(logs: Logs) { - logs.validate() + override fun visitStoredCompletions(storedCompletions: StoredCompletions) { + storedCompletions.validate() } } ) @@ -886,7 +900,8 @@ private constructor( object : Visitor { override fun visitCustom(custom: Custom) = custom.validity() - override fun visitLogs(logs: Logs) = logs.validity() + override fun visitStoredCompletions(storedCompletions: StoredCompletions) = + storedCompletions.validity() override fun unknown(json: JsonValue?) = 0 } @@ -897,15 +912,16 @@ private constructor( return true } - return /* spotless:off */ other is DataSourceConfig && custom == other.custom && logs == other.logs /* spotless:on */ + return /* spotless:off */ other is DataSourceConfig && custom == other.custom && storedCompletions == other.storedCompletions /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(custom, logs) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(custom, storedCompletions) /* spotless:on */ override fun toString(): String = when { custom != null -> "DataSourceConfig{custom=$custom}" - logs != null -> "DataSourceConfig{logs=$logs}" + storedCompletions != null -> + "DataSourceConfig{storedCompletions=$storedCompletions}" _json != null -> "DataSourceConfig{_unknown=$_json}" else -> throw IllegalStateException("Invalid DataSourceConfig") } @@ -925,7 +941,9 @@ private constructor( * A data source config which specifies the metadata property of your stored completions * query. This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. */ - @JvmStatic fun ofLogs(logs: Logs) = DataSourceConfig(logs = logs) + @JvmStatic + fun ofStoredCompletions(storedCompletions: StoredCompletions) = + DataSourceConfig(storedCompletions = storedCompletions) } /** @@ -947,7 +965,7 @@ private constructor( * A data source config which specifies the metadata property of your stored completions * query. This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. */ - fun visitLogs(logs: Logs): T + fun visitStoredCompletions(storedCompletions: StoredCompletions): T /** * Maps an unknown variant of [DataSourceConfig] to a value of type [T]. @@ -976,9 +994,9 @@ private constructor( DataSourceConfig(custom = it, _json = json) } ?: DataSourceConfig(_json = json) } - "logs" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - DataSourceConfig(logs = it, _json = json) + "stored_completions" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + DataSourceConfig(storedCompletions = it, _json = json) } ?: DataSourceConfig(_json = json) } } @@ -996,7 +1014,8 @@ private constructor( ) { when { value.custom != null -> generator.writeObject(value.custom) - value.logs != null -> generator.writeObject(value.logs) + value.storedCompletions != null -> + generator.writeObject(value.storedCompletions) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid DataSourceConfig") } @@ -1376,7 +1395,7 @@ private constructor( * A data source config which specifies the metadata property of your stored completions * query. This is usually metadata like `usecase=chatbot` or `prompt-version=v2`, etc. */ - class Logs + class StoredCompletions private constructor( private val type: JsonValue, private val metadata: JsonField, @@ -1392,11 +1411,11 @@ private constructor( ) : this(type, metadata, mutableMapOf()) /** - * The type of data source. Always `logs`. + * The type of data source. Always `stored_completions`. * * Expected to always return the following: * ```java - * JsonValue.from("logs") + * JsonValue.from("stored_completions") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1405,7 +1424,7 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * Metadata filters for the logs data source. + * Metadata filters for the stored completions data source. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -1436,22 +1455,24 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Logs]. */ + /** + * Returns a mutable builder for constructing an instance of [StoredCompletions]. + */ @JvmStatic fun builder() = Builder() } - /** A builder for [Logs]. */ + /** A builder for [StoredCompletions]. */ class Builder internal constructor() { - private var type: JsonValue = JsonValue.from("logs") + private var type: JsonValue = JsonValue.from("stored_completions") private var metadata: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(logs: Logs) = apply { - type = logs.type - metadata = logs.metadata - additionalProperties = logs.additionalProperties.toMutableMap() + internal fun from(storedCompletions: StoredCompletions) = apply { + type = storedCompletions.type + metadata = storedCompletions.metadata + additionalProperties = storedCompletions.additionalProperties.toMutableMap() } /** @@ -1460,7 +1481,7 @@ private constructor( * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("logs") + * JsonValue.from("stored_completions") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -1468,7 +1489,7 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** Metadata filters for the logs data source. */ + /** Metadata filters for the stored completions data source. */ fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) /** @@ -1503,22 +1524,23 @@ private constructor( } /** - * Returns an immutable instance of [Logs]. + * Returns an immutable instance of [StoredCompletions]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): Logs = Logs(type, metadata, additionalProperties.toMutableMap()) + fun build(): StoredCompletions = + StoredCompletions(type, metadata, additionalProperties.toMutableMap()) } private var validated: Boolean = false - fun validate(): Logs = apply { + fun validate(): StoredCompletions = apply { if (validated) { return@apply } _type().let { - if (it != JsonValue.from("logs")) { + if (it != JsonValue.from("stored_completions")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } @@ -1542,10 +1564,10 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - type.let { if (it == JsonValue.from("logs")) 1 else 0 } + + type.let { if (it == JsonValue.from("stored_completions")) 1 else 0 } + (metadata.asKnown().getOrNull()?.validity() ?: 0) - /** Metadata filters for the logs data source. */ + /** Metadata filters for the stored completions data source. */ class Metadata @JsonCreator private constructor( @@ -1657,7 +1679,7 @@ private constructor( return true } - return /* spotless:off */ other is Logs && type == other.type && metadata == other.metadata && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is StoredCompletions && type == other.type && metadata == other.metadata && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ @@ -1667,7 +1689,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Logs{type=$type, metadata=$metadata, additionalProperties=$additionalProperties}" + "StoredCompletions{type=$type, metadata=$metadata, additionalProperties=$additionalProperties}" } } @@ -1679,8 +1701,8 @@ private constructor( class TestingCriterion private constructor( private val labelModel: LabelModel? = null, - private val stringCheck: EvalStringCheckGrader? = null, - private val textSimilarity: EvalTextSimilarityGrader? = null, + private val stringCheck: StringCheckGrader? = null, + private val textSimilarity: TextSimilarity? = null, private val python: Python? = null, private val scoreModel: ScoreModel? = null, private val _json: JsonValue? = null, @@ -1696,11 +1718,10 @@ private constructor( * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + fun stringCheck(): Optional = Optional.ofNullable(stringCheck) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun textSimilarity(): Optional = - Optional.ofNullable(textSimilarity) + fun textSimilarity(): Optional = Optional.ofNullable(textSimilarity) /** A PythonGrader object that runs a python script on the input. */ fun python(): Optional = Optional.ofNullable(python) @@ -1728,11 +1749,10 @@ private constructor( * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun asStringCheck(): EvalStringCheckGrader = stringCheck.getOrThrow("stringCheck") + fun asStringCheck(): StringCheckGrader = stringCheck.getOrThrow("stringCheck") /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun asTextSimilarity(): EvalTextSimilarityGrader = - textSimilarity.getOrThrow("textSimilarity") + fun asTextSimilarity(): TextSimilarity = textSimilarity.getOrThrow("textSimilarity") /** A PythonGrader object that runs a python script on the input. */ fun asPython(): Python = python.getOrThrow("python") @@ -1765,11 +1785,11 @@ private constructor( labelModel.validate() } - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) { + override fun visitStringCheck(stringCheck: StringCheckGrader) { stringCheck.validate() } - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) { + override fun visitTextSimilarity(textSimilarity: TextSimilarity) { textSimilarity.validate() } @@ -1805,10 +1825,10 @@ private constructor( object : Visitor { override fun visitLabelModel(labelModel: LabelModel) = labelModel.validity() - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) = + override fun visitStringCheck(stringCheck: StringCheckGrader) = stringCheck.validity() - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = + override fun visitTextSimilarity(textSimilarity: TextSimilarity) = textSimilarity.validity() override fun visitPython(python: Python) = python.validity() @@ -1854,12 +1874,12 @@ private constructor( * reference using a specified operation. */ @JvmStatic - fun ofStringCheck(stringCheck: EvalStringCheckGrader) = + fun ofStringCheck(stringCheck: StringCheckGrader) = TestingCriterion(stringCheck = stringCheck) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ @JvmStatic - fun ofTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = + fun ofTextSimilarity(textSimilarity: TextSimilarity) = TestingCriterion(textSimilarity = textSimilarity) /** A PythonGrader object that runs a python script on the input. */ @@ -1886,10 +1906,10 @@ private constructor( * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ - fun visitStringCheck(stringCheck: EvalStringCheckGrader): T + fun visitStringCheck(stringCheck: StringCheckGrader): T /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader): T + fun visitTextSimilarity(textSimilarity: TextSimilarity): T /** A PythonGrader object that runs a python script on the input. */ fun visitPython(python: Python): T @@ -1925,14 +1945,14 @@ private constructor( } ?: TestingCriterion(_json = json) } "string_check" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { + return tryDeserialize(node, jacksonTypeRef())?.let { TestingCriterion(stringCheck = it, _json = json) } ?: TestingCriterion(_json = json) } "text_similarity" -> { - return tryDeserialize(node, jacksonTypeRef()) - ?.let { TestingCriterion(textSimilarity = it, _json = json) } - ?: TestingCriterion(_json = json) + return tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(textSimilarity = it, _json = json) + } ?: TestingCriterion(_json = json) } "python" -> { return tryDeserialize(node, jacksonTypeRef())?.let { @@ -3819,31 +3839,63 @@ private constructor( "LabelModel{input=$input, labels=$labels, model=$model, name=$name, passingLabels=$passingLabels, type=$type, additionalProperties=$additionalProperties}" } - /** A PythonGrader object that runs a python script on the input. */ - class Python + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + class TextSimilarity private constructor( + private val evaluationMetric: JsonField, + private val input: JsonField, private val name: JsonField, - private val source: JsonField, + private val reference: JsonField, private val type: JsonValue, - private val imageTag: JsonField, private val passThreshold: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( + @JsonProperty("evaluation_metric") + @ExcludeMissing + evaluationMetric: JsonField = + JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("source") + @JsonProperty("reference") @ExcludeMissing - source: JsonField = JsonMissing.of(), + reference: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - @JsonProperty("image_tag") - @ExcludeMissing - imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) + ) : this(evaluationMetric, input, name, reference, type, passThreshold, mutableMapOf()) + + fun toTextSimilarityGrader(): TextSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(evaluationMetric) + .input(input) + .name(name) + .reference(reference) + .type(type) + .build() + + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun evaluationMetric(): TextSimilarityGrader.EvaluationMetric = + evaluationMetric.getRequired("evaluation_metric") + + /** + * The text being graded. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): String = input.getRequired("input") /** * The name of the grader. @@ -3855,20 +3907,20 @@ private constructor( fun name(): String = name.getRequired("name") /** - * The source code of the python script. + * The text being graded against. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun source(): String = source.getRequired("source") + fun reference(): String = reference.getRequired("reference") /** - * The object type, which is always `python`. + * The type of grader. * * Expected to always return the following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -3877,42 +3929,48 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The image tag to use for the python script. + * The threshold for the score. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun imageTag(): Optional = imageTag.getOptional("image_tag") + fun passThreshold(): Double = passThreshold.getRequired("pass_threshold") /** - * The threshold for the score. + * Returns the raw JSON value of [evaluationMetric]. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * Unlike [evaluationMetric], this method doesn't throw if the JSON field has an + * unexpected type. */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + @JsonProperty("evaluation_metric") + @ExcludeMissing + fun _evaluationMetric(): JsonField = + evaluationMetric /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [input]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input /** - * Returns the raw JSON value of [source]. + * Returns the raw JSON value of [name]. * - * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [imageTag]. + * Returns the raw JSON value of [reference]. * - * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * Unlike [reference], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag + @JsonProperty("reference") + @ExcludeMissing + fun _reference(): JsonField = reference /** * Returns the raw JSON value of [passThreshold]. @@ -3939,37 +3997,73 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [Python]. + * Returns a mutable builder for constructing an instance of [TextSimilarity]. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [Python]. */ + /** A builder for [TextSimilarity]. */ class Builder internal constructor() { + private var evaluationMetric: JsonField? = + null + private var input: JsonField? = null private var name: JsonField? = null - private var source: JsonField? = null - private var type: JsonValue = JsonValue.from("python") - private var imageTag: JsonField = JsonMissing.of() - private var passThreshold: JsonField = JsonMissing.of() + private var reference: JsonField? = null + private var type: JsonValue = JsonValue.from("text_similarity") + private var passThreshold: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(python: Python) = apply { - name = python.name - source = python.source - type = python.type - imageTag = python.imageTag - passThreshold = python.passThreshold - additionalProperties = python.additionalProperties.toMutableMap() + internal fun from(textSimilarity: TextSimilarity) = apply { + evaluationMetric = textSimilarity.evaluationMetric + input = textSimilarity.input + name = textSimilarity.name + reference = textSimilarity.reference + type = textSimilarity.type + passThreshold = textSimilarity.passThreshold + additionalProperties = textSimilarity.additionalProperties.toMutableMap() } + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + */ + fun evaluationMetric(evaluationMetric: TextSimilarityGrader.EvaluationMetric) = + evaluationMetric(JsonField.of(evaluationMetric)) + + /** + * Sets [Builder.evaluationMetric] to an arbitrary JSON value. + * + * You should usually call [Builder.evaluationMetric] with a well-typed + * [TextSimilarityGrader.EvaluationMetric] value instead. This method is primarily + * for setting the field to an undocumented or not yet supported value. + */ + fun evaluationMetric( + evaluationMetric: JsonField + ) = apply { this.evaluationMetric = evaluationMetric } + + /** The text being graded. */ + fun input(input: String) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun input(input: JsonField) = apply { this.input = input } + /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -3982,17 +4076,17 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } - /** The source code of the python script. */ - fun source(source: String) = source(JsonField.of(source)) + /** The text being graded against. */ + fun reference(reference: String) = reference(JsonField.of(reference)) /** - * Sets [Builder.source] to an arbitrary JSON value. + * Sets [Builder.reference] to an arbitrary JSON value. * - * You should usually call [Builder.source] with a well-typed [String] value + * You should usually call [Builder.reference] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun source(source: JsonField) = apply { this.source = source } + fun reference(reference: JsonField) = apply { this.reference = reference } /** * Sets the field to an arbitrary JSON value. @@ -4000,7 +4094,7 @@ private constructor( * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -4008,18 +4102,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The image tag to use for the python script. */ - fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) - - /** - * Sets [Builder.imageTag] to an arbitrary JSON value. - * - * You should usually call [Builder.imageTag] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } - /** The threshold for the score. */ fun passThreshold(passThreshold: Double) = passThreshold(JsonField.of(passThreshold)) @@ -4058,44 +4140,49 @@ private constructor( } /** - * Returns an immutable instance of [Python]. + * Returns an immutable instance of [TextSimilarity]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): Python = - Python( + fun build(): TextSimilarity = + TextSimilarity( + checkRequired("evaluationMetric", evaluationMetric), + checkRequired("input", input), checkRequired("name", name), - checkRequired("source", source), + checkRequired("reference", reference), type, - imageTag, - passThreshold, + checkRequired("passThreshold", passThreshold), additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): Python = apply { + fun validate(): TextSimilarity = apply { if (validated) { return@apply } + evaluationMetric().validate() + input() name() - source() + reference() _type().let { - if (it != JsonValue.from("python")) { + if (it != JsonValue.from("text_similarity")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - imageTag() passThreshold() validated = true } @@ -4116,10 +4203,11 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (name.asKnown().isPresent) 1 else 0) + - (if (source.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("python")) 1 else 0 } + - (if (imageTag.asKnown().isPresent) 1 else 0) + + (evaluationMetric.asKnown().getOrNull()?.validity() ?: 0) + + (if (input.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (reference.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -4127,84 +4215,77 @@ private constructor( return true } - return /* spotless:off */ other is Python && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is TextSimilarity && evaluationMetric == other.evaluationMetric && input == other.input && name == other.name && reference == other.reference && type == other.type && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, name, reference, type, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Python{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + "TextSimilarity{evaluationMetric=$evaluationMetric, input=$input, name=$name, reference=$reference, type=$type, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } - /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - class ScoreModel + /** A PythonGrader object that runs a python script on the input. */ + class Python private constructor( - private val input: JsonField>, - private val model: JsonField, private val name: JsonField, + private val source: JsonField, private val type: JsonValue, + private val imageTag: JsonField, private val passThreshold: JsonField, - private val range: JsonField>, - private val samplingParams: JsonValue, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("input") - @ExcludeMissing - input: JsonField> = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("source") + @ExcludeMissing + source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("image_tag") + @ExcludeMissing + imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - @JsonProperty("range") - @ExcludeMissing - range: JsonField> = JsonMissing.of(), - @JsonProperty("sampling_params") - @ExcludeMissing - samplingParams: JsonValue = JsonMissing.of(), - ) : this(input, model, name, type, passThreshold, range, samplingParams, mutableMapOf()) + ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) - /** - * The input text. This may include template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun input(): List = input.getRequired("input") + fun toPythonGrader(): PythonGrader = + PythonGrader.builder() + .name(name) + .source(source) + .type(type) + .imageTag(imageTag) + .build() /** - * The model to use for the evaluation. + * The name of the grader. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun model(): String = model.getRequired("model") + fun name(): String = name.getRequired("name") /** - * The name of the grader. + * The source code of the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun name(): String = name.getRequired("name") + fun source(): String = source.getRequired("source") /** - * The object type, which is always `score_model`. + * The object type, which is always `python`. * * Expected to always return the following: * ```java - * JsonValue.from("score_model") + * JsonValue.from("python") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -4213,46 +4294,42 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The threshold for the score. + * The image tag to use for the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + fun imageTag(): Optional = imageTag.getOptional("image_tag") /** - * The range of the score. Defaults to `[0, 1]`. + * The threshold for the score. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun range(): Optional> = range.getOptional("range") - - /** The sampling parameters for the model. */ - @JsonProperty("sampling_params") - @ExcludeMissing - fun _samplingParams(): JsonValue = samplingParams + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") /** - * Returns the raw JSON value of [input]. + * Returns the raw JSON value of [name]. * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("input") @ExcludeMissing fun _input(): JsonField> = input + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [model]. + * Returns the raw JSON value of [source]. * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [imageTag]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag /** * Returns the raw JSON value of [passThreshold]. @@ -4264,13 +4341,6 @@ private constructor( @ExcludeMissing fun _passThreshold(): JsonField = passThreshold - /** - * Returns the raw JSON value of [range]. - * - * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -4286,80 +4356,37 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [ScoreModel]. + * Returns a mutable builder for constructing an instance of [Python]. * * The following fields are required: * ```java - * .input() - * .model() * .name() + * .source() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [ScoreModel]. */ + /** A builder for [Python]. */ class Builder internal constructor() { - private var input: JsonField>? = null - private var model: JsonField? = null private var name: JsonField? = null - private var type: JsonValue = JsonValue.from("score_model") + private var source: JsonField? = null + private var type: JsonValue = JsonValue.from("python") + private var imageTag: JsonField = JsonMissing.of() private var passThreshold: JsonField = JsonMissing.of() - private var range: JsonField>? = null - private var samplingParams: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(scoreModel: ScoreModel) = apply { - input = scoreModel.input.map { it.toMutableList() } - model = scoreModel.model - name = scoreModel.name - type = scoreModel.type - passThreshold = scoreModel.passThreshold - range = scoreModel.range.map { it.toMutableList() } - samplingParams = scoreModel.samplingParams - additionalProperties = scoreModel.additionalProperties.toMutableMap() + internal fun from(python: Python) = apply { + name = python.name + source = python.source + type = python.type + imageTag = python.imageTag + passThreshold = python.passThreshold + additionalProperties = python.additionalProperties.toMutableMap() } - /** The input text. This may include template strings. */ - fun input(input: List) = input(JsonField.of(input)) - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun input(input: JsonField>) = apply { - this.input = input.map { it.toMutableList() } - } - - /** - * Adds a single [Input] to [Builder.input]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addInput(input: Input) = apply { - this.input = - (this.input ?: JsonField.of(mutableListOf())).also { - checkKnown("input", it).add(input) - } - } - - /** The model to use for the evaluation. */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -4372,13 +4399,25 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** The source code of the python script. */ + fun source(source: String) = source(JsonField.of(source)) + + /** + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + /** * Sets the field to an arbitrary JSON value. * * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("score_model") + * JsonValue.from("python") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -4386,50 +4425,31 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The threshold for the score. */ - fun passThreshold(passThreshold: Double) = - passThreshold(JsonField.of(passThreshold)) + /** The image tag to use for the python script. */ + fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) /** - * Sets [Builder.passThreshold] to an arbitrary JSON value. + * Sets [Builder.imageTag] to an arbitrary JSON value. * - * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * You should usually call [Builder.imageTag] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun passThreshold(passThreshold: JsonField) = apply { - this.passThreshold = passThreshold - } + fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } - /** The range of the score. Defaults to `[0, 1]`. */ - fun range(range: List) = range(JsonField.of(range)) + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) /** - * Sets [Builder.range] to an arbitrary JSON value. + * Sets [Builder.passThreshold] to an arbitrary JSON value. * - * You should usually call [Builder.range] with a well-typed `List` value + * You should usually call [Builder.passThreshold] with a well-typed [Double] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun range(range: JsonField>) = apply { - this.range = range.map { it.toMutableList() } - } - - /** - * Adds a single [Double] to [Builder.range]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addRange(range: Double) = apply { - this.range = - (this.range ?: JsonField.of(mutableListOf())).also { - checkKnown("range", it).add(range) - } - } - - /** The sampling parameters for the model. */ - fun samplingParams(samplingParams: JsonValue) = apply { - this.samplingParams = samplingParams + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold } fun additionalProperties(additionalProperties: Map) = apply { @@ -4455,49 +4475,45 @@ private constructor( } /** - * Returns an immutable instance of [ScoreModel]. + * Returns an immutable instance of [Python]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java - * .input() - * .model() * .name() + * .source() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): ScoreModel = - ScoreModel( - checkRequired("input", input).map { it.toImmutable() }, - checkRequired("model", model), + fun build(): Python = + Python( checkRequired("name", name), + checkRequired("source", source), type, + imageTag, passThreshold, - (range ?: JsonMissing.of()).map { it.toImmutable() }, - samplingParams, additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): ScoreModel = apply { + fun validate(): Python = apply { if (validated) { return@apply } - input().forEach { it.validate() } - model() name() + source() _type().let { - if (it != JsonValue.from("score_model")) { + if (it != JsonValue.from("python")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } + imageTag() passThreshold() - range() validated = true } @@ -4517,1007 +4533,442 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (input.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + - (if (model.asKnown().isPresent) 1 else 0) + - (if (name.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + - (if (passThreshold.asKnown().isPresent) 1 else 0) + - (range.asKnown().getOrNull()?.size ?: 0) - - /** - * A message input to the model with a role indicating instruction following hierarchy. - * Instructions given with the `developer` or `system` role take precedence over - * instructions given with the `user` role. Messages with the `assistant` role are - * presumed to have been generated by the model in previous interactions. - */ - class Input - private constructor( - private val content: JsonField, - private val role: JsonField, - private val type: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("content") - @ExcludeMissing - content: JsonField = JsonMissing.of(), - @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(content, role, type, mutableMapOf()) - - /** - * Text inputs to the model - can contain template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun content(): Content = content.getRequired("content") + (if (name.asKnown().isPresent) 1 else 0) + + (if (source.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("python")) 1 else 0 } + + (if (imageTag.asKnown().isPresent) 1 else 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun role(): Role = role.getRequired("role") + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } - /** - * The type of the message input. Always `message`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") + return /* spotless:off */ other is Python && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + } - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("content") - @ExcludeMissing - fun _content(): JsonField = content + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + /* spotless:on */ - /** - * Returns the raw JSON value of [role]. - * - * Unlike [role], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + override fun hashCode(): Int = hashCode - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + override fun toString() = + "Python{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + } - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + class ScoreModel + private constructor( + private val input: JsonField>, + private val model: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val range: JsonField>, + private val samplingParams: JsonValue, + private val passThreshold: JsonField, + private val additionalProperties: MutableMap, + ) { - @JsonAnyGetter + @JsonCreator + private constructor( + @JsonProperty("input") + @ExcludeMissing + input: JsonField> = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("range") + @ExcludeMissing + range: JsonField> = JsonMissing.of(), + @JsonProperty("sampling_params") + @ExcludeMissing + samplingParams: JsonValue = JsonMissing.of(), + @JsonProperty("pass_threshold") @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) + passThreshold: JsonField = JsonMissing.of(), + ) : this(input, model, name, type, range, samplingParams, passThreshold, mutableMapOf()) + + fun toScoreModelGrader(): ScoreModelGrader = + ScoreModelGrader.builder() + .input(input) + .model(model) + .name(name) + .type(type) + .range(range) + .samplingParams(samplingParams) + .build() - fun toBuilder() = Builder().from(this) + /** + * The input text. This may include template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): List = input.getRequired("input") - companion object { + /** + * The model to use for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun model(): String = model.getRequired("model") - /** - * Returns a mutable builder for constructing an instance of [Input]. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - */ - @JvmStatic fun builder() = Builder() - } + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") - /** A builder for [Input]. */ - class Builder internal constructor() { + /** + * The object type, which is always `score_model`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - private var content: JsonField? = null - private var role: JsonField? = null - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() + /** + * The range of the score. Defaults to `[0, 1]`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun range(): Optional> = range.getOptional("range") - @JvmSynthetic - internal fun from(input: Input) = apply { - content = input.content - role = input.role - type = input.type - additionalProperties = input.additionalProperties.toMutableMap() - } + /** The sampling parameters for the model. */ + @JsonProperty("sampling_params") + @ExcludeMissing + fun _samplingParams(): JsonValue = samplingParams - /** Text inputs to the model - can contain template strings. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun content(content: JsonField) = apply { this.content = content } + /** + * The threshold for the score. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") - /** Alias for calling [content] with `Content.ofTextInput(textInput)`. */ - fun content(textInput: String) = content(Content.ofTextInput(textInput)) + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") + @ExcludeMissing + fun _input(): JsonField> = input - /** - * Alias for calling [content] with - * `Content.ofResponseInputText(responseInputText)`. - */ - fun content(responseInputText: ResponseInputText) = - content(Content.ofResponseInputText(responseInputText)) + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model - /** Alias for calling [content] with `Content.ofOutputText(outputText)`. */ - fun content(outputText: Content.OutputText) = - content(Content.ofOutputText(outputText)) + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - fun role(role: Role) = role(JsonField.of(role)) + /** + * Returns the raw JSON value of [range]. + * + * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range - /** - * Sets [Builder.role] to an arbitrary JSON value. - * - * You should usually call [Builder.role] with a well-typed [Role] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun role(role: JsonField) = apply { this.role = role } + /** + * Returns the raw JSON value of [passThreshold]. + * + * Unlike [passThreshold], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pass_threshold") + @ExcludeMissing + fun _passThreshold(): JsonField = passThreshold - /** The type of the message input. Always `message`. */ - fun type(type: Type) = type(JsonField.of(type)) + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + fun toBuilder() = Builder().from(this) - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + companion object { - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } + /** + * Returns a mutable builder for constructing an instance of [ScoreModel]. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } + /** A builder for [ScoreModel]. */ + class Builder internal constructor() { - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + private var input: JsonField>? = null + private var model: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("score_model") + private var range: JsonField>? = null + private var samplingParams: JsonValue = JsonMissing.of() + private var passThreshold: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() - /** - * Returns an immutable instance of [Input]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Input = - Input( - checkRequired("content", content), - checkRequired("role", role), - type, - additionalProperties.toMutableMap(), - ) + @JvmSynthetic + internal fun from(scoreModel: ScoreModel) = apply { + input = scoreModel.input.map { it.toMutableList() } + model = scoreModel.model + name = scoreModel.name + type = scoreModel.type + range = scoreModel.range.map { it.toMutableList() } + samplingParams = scoreModel.samplingParams + passThreshold = scoreModel.passThreshold + additionalProperties = scoreModel.additionalProperties.toMutableMap() } - private var validated: Boolean = false - - fun validate(): Input = apply { - if (validated) { - return@apply - } + /** The input text. This may include template strings. */ + fun input(input: List) = input(JsonField.of(input)) - content().validate() - role().validate() - type().ifPresent { it.validate() } - validated = true + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField>) = apply { + this.input = input.map { it.toMutableList() } } - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. + * Adds a single [ScoreModelGrader.Input] to [Builder.input]. * - * Used for best match union deserialization. + * @throws IllegalStateException if the field was previously set to a non-list. */ - @JvmSynthetic - internal fun validity(): Int = - (content.asKnown().getOrNull()?.validity() ?: 0) + - (role.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) - - /** Text inputs to the model - can contain template strings. */ - @JsonDeserialize(using = Content.Deserializer::class) - @JsonSerialize(using = Content.Serializer::class) - class Content - private constructor( - private val textInput: String? = null, - private val responseInputText: ResponseInputText? = null, - private val outputText: OutputText? = null, - private val _json: JsonValue? = null, - ) { + fun addInput(input: ScoreModelGrader.Input) = apply { + this.input = + (this.input ?: JsonField.of(mutableListOf())).also { + checkKnown("input", it).add(input) + } + } - /** A text input to the model. */ - fun textInput(): Optional = Optional.ofNullable(textInput) + /** The model to use for the evaluation. */ + fun model(model: String) = model(JsonField.of(model)) - /** A text input to the model. */ - fun responseInputText(): Optional = - Optional.ofNullable(responseInputText) + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } - /** A text output from the model. */ - fun outputText(): Optional = Optional.ofNullable(outputText) + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) - fun isTextInput(): Boolean = textInput != null + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } - fun isResponseInputText(): Boolean = responseInputText != null + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } - fun isOutputText(): Boolean = outputText != null + /** The range of the score. Defaults to `[0, 1]`. */ + fun range(range: List) = range(JsonField.of(range)) - /** A text input to the model. */ - fun asTextInput(): String = textInput.getOrThrow("textInput") + /** + * Sets [Builder.range] to an arbitrary JSON value. + * + * You should usually call [Builder.range] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun range(range: JsonField>) = apply { + this.range = range.map { it.toMutableList() } + } - /** A text input to the model. */ - fun asResponseInputText(): ResponseInputText = - responseInputText.getOrThrow("responseInputText") + /** + * Adds a single [Double] to [Builder.range]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRange(range: Double) = apply { + this.range = + (this.range ?: JsonField.of(mutableListOf())).also { + checkKnown("range", it).add(range) + } + } - /** A text output from the model. */ - fun asOutputText(): OutputText = outputText.getOrThrow("outputText") + /** The sampling parameters for the model. */ + fun samplingParams(samplingParams: JsonValue) = apply { + this.samplingParams = samplingParams + } - fun _json(): Optional = Optional.ofNullable(_json) + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) - fun accept(visitor: Visitor): T = - when { - textInput != null -> visitor.visitTextInput(textInput) - responseInputText != null -> - visitor.visitResponseInputText(responseInputText) - outputText != null -> visitor.visitOutputText(outputText) - else -> visitor.unknown(_json) - } + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } - private var validated: Boolean = false + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } - fun validate(): Content = apply { - if (validated) { - return@apply - } + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } - accept( - object : Visitor { - override fun visitTextInput(textInput: String) {} + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) { - responseInputText.validate() - } + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } - override fun visitOutputText(outputText: OutputText) { - outputText.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitTextInput(textInput: String) = 1 - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) = responseInputText.validity() - - override fun visitOutputText(outputText: OutputText) = - outputText.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && textInput == other.textInput && responseInputText == other.responseInputText && outputText == other.outputText /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(textInput, responseInputText, outputText) /* spotless:on */ - - override fun toString(): String = - when { - textInput != null -> "Content{textInput=$textInput}" - responseInputText != null -> - "Content{responseInputText=$responseInputText}" - outputText != null -> "Content{outputText=$outputText}" - _json != null -> "Content{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Content") - } - - companion object { - - /** A text input to the model. */ - @JvmStatic - fun ofTextInput(textInput: String) = Content(textInput = textInput) - - /** A text input to the model. */ - @JvmStatic - fun ofResponseInputText(responseInputText: ResponseInputText) = - Content(responseInputText = responseInputText) - - /** A text output from the model. */ - @JvmStatic - fun ofOutputText(outputText: OutputText) = Content(outputText = outputText) - } - - /** - * An interface that defines how to map each variant of [Content] to a value of - * type [T]. - */ - interface Visitor { - - /** A text input to the model. */ - fun visitTextInput(textInput: String): T - - /** A text input to the model. */ - fun visitResponseInputText(responseInputText: ResponseInputText): T - - /** A text output from the model. */ - fun visitOutputText(outputText: OutputText): T - - /** - * Maps an unknown variant of [Content] to a value of type [T]. - * - * An instance of [Content] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Content: $json") - } - } - - internal class Deserializer : BaseDeserializer(Content::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Content { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Content(responseInputText = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(outputText = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(textInput = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from array). - 0 -> Content(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Content::class) { - - override fun serialize( - value: Content, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.textInput != null -> generator.writeObject(value.textInput) - value.responseInputText != null -> - generator.writeObject(value.responseInputText) - value.outputText != null -> generator.writeObject(value.outputText) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Content") - } - } - } - - /** A text output from the model. */ - class OutputText - private constructor( - private val text: JsonField, - private val type: JsonValue, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("text") - @ExcludeMissing - text: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - ) : this(text, type, mutableMapOf()) - - /** - * The text output from the model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded - * with an unexpected value). - */ - fun text(): String = text.getRequired("text") - - /** - * The type of the output text. Always `output_text`. - * - * Expected to always return the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * However, this method can be useful for debugging and logging (e.g. if the - * server responded with an unexpected value). - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - - /** - * Returns the raw JSON value of [text]. - * - * Unlike [text], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [OutputText]. - * - * The following fields are required: - * ```java - * .text() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [OutputText]. */ - class Builder internal constructor() { - - private var text: JsonField? = null - private var type: JsonValue = JsonValue.from("output_text") - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(outputText: OutputText) = apply { - text = outputText.text - type = outputText.type - additionalProperties = - outputText.additionalProperties.toMutableMap() - } - - /** The text output from the model. */ - fun text(text: String) = text(JsonField.of(text)) - - /** - * Sets [Builder.text] to an arbitrary JSON value. - * - * You should usually call [Builder.text] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun text(text: JsonField) = apply { this.text = text } - - /** - * Sets the field to an arbitrary JSON value. - * - * It is usually unnecessary to call this method because the field - * defaults to the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonValue) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [OutputText]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - * - * The following fields are required: - * ```java - * .text() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): OutputText = - OutputText( - checkRequired("text", text), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): OutputText = apply { - if (validated) { - return@apply - } - - text() - _type().let { - if (it != JsonValue.from("output_text")) { - throw OpenAIInvalidDataException( - "'type' is invalid, received $it" - ) - } - } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (text.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("output_text")) 1 else 0 } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is OutputText && text == other.text && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(text, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "OutputText{text=$text, type=$type, additionalProperties=$additionalProperties}" - } - } + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. + * Returns an immutable instance of [ScoreModel]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ - class Role @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val USER = of("user") - - @JvmField val ASSISTANT = of("assistant") - - @JvmField val SYSTEM = of("system") - - @JvmField val DEVELOPER = of("developer") - - @JvmStatic fun of(value: String) = Role(JsonField.of(value)) - } - - /** An enum containing [Role]'s known values. */ - enum class Known { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - } - - /** - * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Role] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - /** - * An enum member indicating that [Role] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - USER -> Value.USER - ASSISTANT -> Value.ASSISTANT - SYSTEM -> Value.SYSTEM - DEVELOPER -> Value.DEVELOPER - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - USER -> Known.USER - ASSISTANT -> Known.ASSISTANT - SYSTEM -> Known.SYSTEM - DEVELOPER -> Known.DEVELOPER - else -> throw OpenAIInvalidDataException("Unknown Role: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Role = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Role && value == other.value /* spotless:on */ - } + fun build(): ScoreModel = + ScoreModel( + checkRequired("input", input).map { it.toImmutable() }, + checkRequired("model", model), + checkRequired("name", name), + type, + (range ?: JsonMissing.of()).map { it.toImmutable() }, + samplingParams, + passThreshold, + additionalProperties.toMutableMap(), + ) + } - override fun hashCode() = value.hashCode() + private var validated: Boolean = false - override fun toString() = value.toString() + fun validate(): ScoreModel = apply { + if (validated) { + return@apply } - /** The type of the message input. Always `message`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val MESSAGE = of("message") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - MESSAGE - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - MESSAGE, - /** - * An enum member indicating that [Type] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - MESSAGE -> Value.MESSAGE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - MESSAGE -> Known.MESSAGE - else -> throw OpenAIInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Type && value == other.value /* spotless:on */ + input().forEach { it.validate() } + model() + name() + _type().let { + if (it != JsonValue.from("score_model")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() } + range() + passThreshold() + validated = true + } - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Input && content == other.content && role == other.role && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false } - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(content, role, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Input{content=$content, role=$role, type=$type, additionalProperties=$additionalProperties}" - } + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (input.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (model.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + + (range.asKnown().getOrNull()?.size ?: 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && passThreshold == other.passThreshold && range == other.range && samplingParams == other.samplingParams && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is ScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && range == other.range && samplingParams == other.samplingParams && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(input, model, name, type, passThreshold, range, samplingParams, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(input, model, name, type, range, samplingParams, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "ScoreModel{input=$input, model=$model, name=$name, type=$type, passThreshold=$passThreshold, range=$range, samplingParams=$samplingParams, additionalProperties=$additionalProperties}" + "ScoreModel{input=$input, model=$model, name=$name, type=$type, range=$range, samplingParams=$samplingParams, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateResponse.kt index 40073b39a..0982511fe 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateResponse.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalCreateResponse.kt @@ -15,7 +15,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.BaseDeserializer import com.openai.core.BaseSerializer -import com.openai.core.Enum import com.openai.core.ExcludeMissing import com.openai.core.JsonField import com.openai.core.JsonMissing @@ -26,7 +25,11 @@ import com.openai.core.checkRequired import com.openai.core.getOrThrow import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException -import com.openai.models.responses.ResponseInputText +import com.openai.models.graders.gradermodels.LabelModelGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader import java.util.Collections import java.util.Objects import java.util.Optional @@ -388,34 +391,43 @@ private constructor( } /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofLabelModel(labelModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofLabelModelGrader(labelModelGrader)`. */ - fun addTestingCriterion(labelModel: EvalLabelModelGrader) = - addTestingCriterion(TestingCriterion.ofLabelModel(labelModel)) + fun addTestingCriterion(labelModelGrader: LabelModelGrader) = + addTestingCriterion(TestingCriterion.ofLabelModelGrader(labelModelGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofStringCheck(stringCheck)`. + * `TestingCriterion.ofStringCheckGrader(stringCheckGrader)`. */ - fun addTestingCriterion(stringCheck: EvalStringCheckGrader) = - addTestingCriterion(TestingCriterion.ofStringCheck(stringCheck)) + fun addTestingCriterion(stringCheckGrader: StringCheckGrader) = + addTestingCriterion(TestingCriterion.ofStringCheckGrader(stringCheckGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofTextSimilarity(textSimilarity)`. + * `TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity)`. */ - fun addTestingCriterion(textSimilarity: EvalTextSimilarityGrader) = - addTestingCriterion(TestingCriterion.ofTextSimilarity(textSimilarity)) + fun addTestingCriterion( + evalGraderTextSimilarity: TestingCriterion.EvalGraderTextSimilarity + ) = + addTestingCriterion( + TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity) + ) - /** Alias for calling [addTestingCriterion] with `TestingCriterion.ofPython(python)`. */ - fun addTestingCriterion(python: TestingCriterion.Python) = - addTestingCriterion(TestingCriterion.ofPython(python)) + /** + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderPython(evalGraderPython)`. + */ + fun addTestingCriterion(evalGraderPython: TestingCriterion.EvalGraderPython) = + addTestingCriterion(TestingCriterion.ofEvalGraderPython(evalGraderPython)) /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofScoreModel(scoreModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)`. */ - fun addTestingCriterion(scoreModel: TestingCriterion.ScoreModel) = - addTestingCriterion(TestingCriterion.ofScoreModel(scoreModel)) + fun addTestingCriterion(evalGraderScoreModel: TestingCriterion.EvalGraderScoreModel) = + addTestingCriterion(TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)) fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -860,11 +872,11 @@ private constructor( @JsonSerialize(using = TestingCriterion.Serializer::class) class TestingCriterion private constructor( - private val labelModel: EvalLabelModelGrader? = null, - private val stringCheck: EvalStringCheckGrader? = null, - private val textSimilarity: EvalTextSimilarityGrader? = null, - private val python: Python? = null, - private val scoreModel: ScoreModel? = null, + private val labelModelGrader: LabelModelGrader? = null, + private val stringCheckGrader: StringCheckGrader? = null, + private val evalGraderTextSimilarity: EvalGraderTextSimilarity? = null, + private val evalGraderPython: EvalGraderPython? = null, + private val evalGraderScoreModel: EvalGraderScoreModel? = null, private val _json: JsonValue? = null, ) { @@ -872,65 +884,71 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun labelModel(): Optional = Optional.ofNullable(labelModel) + fun labelModelGrader(): Optional = Optional.ofNullable(labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + fun stringCheckGrader(): Optional = + Optional.ofNullable(stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun textSimilarity(): Optional = - Optional.ofNullable(textSimilarity) + fun evalGraderTextSimilarity(): Optional = + Optional.ofNullable(evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - fun python(): Optional = Optional.ofNullable(python) + fun evalGraderPython(): Optional = Optional.ofNullable(evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + fun evalGraderScoreModel(): Optional = + Optional.ofNullable(evalGraderScoreModel) - fun isLabelModel(): Boolean = labelModel != null + fun isLabelModelGrader(): Boolean = labelModelGrader != null - fun isStringCheck(): Boolean = stringCheck != null + fun isStringCheckGrader(): Boolean = stringCheckGrader != null - fun isTextSimilarity(): Boolean = textSimilarity != null + fun isEvalGraderTextSimilarity(): Boolean = evalGraderTextSimilarity != null - fun isPython(): Boolean = python != null + fun isEvalGraderPython(): Boolean = evalGraderPython != null - fun isScoreModel(): Boolean = scoreModel != null + fun isEvalGraderScoreModel(): Boolean = evalGraderScoreModel != null /** * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun asLabelModel(): EvalLabelModelGrader = labelModel.getOrThrow("labelModel") + fun asLabelModelGrader(): LabelModelGrader = labelModelGrader.getOrThrow("labelModelGrader") /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun asStringCheck(): EvalStringCheckGrader = stringCheck.getOrThrow("stringCheck") + fun asStringCheckGrader(): StringCheckGrader = + stringCheckGrader.getOrThrow("stringCheckGrader") /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun asTextSimilarity(): EvalTextSimilarityGrader = - textSimilarity.getOrThrow("textSimilarity") + fun asEvalGraderTextSimilarity(): EvalGraderTextSimilarity = + evalGraderTextSimilarity.getOrThrow("evalGraderTextSimilarity") /** A PythonGrader object that runs a python script on the input. */ - fun asPython(): Python = python.getOrThrow("python") + fun asEvalGraderPython(): EvalGraderPython = evalGraderPython.getOrThrow("evalGraderPython") /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun asScoreModel(): ScoreModel = scoreModel.getOrThrow("scoreModel") + fun asEvalGraderScoreModel(): EvalGraderScoreModel = + evalGraderScoreModel.getOrThrow("evalGraderScoreModel") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { - labelModel != null -> visitor.visitLabelModel(labelModel) - stringCheck != null -> visitor.visitStringCheck(stringCheck) - textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) - python != null -> visitor.visitPython(python) - scoreModel != null -> visitor.visitScoreModel(scoreModel) + labelModelGrader != null -> visitor.visitLabelModelGrader(labelModelGrader) + stringCheckGrader != null -> visitor.visitStringCheckGrader(stringCheckGrader) + evalGraderTextSimilarity != null -> + visitor.visitEvalGraderTextSimilarity(evalGraderTextSimilarity) + evalGraderPython != null -> visitor.visitEvalGraderPython(evalGraderPython) + evalGraderScoreModel != null -> + visitor.visitEvalGraderScoreModel(evalGraderScoreModel) else -> visitor.unknown(_json) } @@ -943,24 +961,28 @@ private constructor( accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) { - labelModel.validate() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) { + labelModelGrader.validate() } - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) { - stringCheck.validate() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) { + stringCheckGrader.validate() } - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) { - textSimilarity.validate() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) { + evalGraderTextSimilarity.validate() } - override fun visitPython(python: Python) { - python.validate() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) { + evalGraderPython.validate() } - override fun visitScoreModel(scoreModel: ScoreModel) { - scoreModel.validate() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) { + evalGraderScoreModel.validate() } } ) @@ -985,18 +1007,22 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) = - labelModel.validity() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) = + labelModelGrader.validity() - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) = - stringCheck.validity() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) = + stringCheckGrader.validity() - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - textSimilarity.validity() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) = evalGraderTextSimilarity.validity() - override fun visitPython(python: Python) = python.validity() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) = + evalGraderPython.validity() - override fun visitScoreModel(scoreModel: ScoreModel) = scoreModel.validity() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) = evalGraderScoreModel.validity() override fun unknown(json: JsonValue?) = 0 } @@ -1007,18 +1033,21 @@ private constructor( return true } - return /* spotless:off */ other is TestingCriterion && labelModel == other.labelModel && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel /* spotless:on */ + return /* spotless:off */ other is TestingCriterion && labelModelGrader == other.labelModelGrader && stringCheckGrader == other.stringCheckGrader && evalGraderTextSimilarity == other.evalGraderTextSimilarity && evalGraderPython == other.evalGraderPython && evalGraderScoreModel == other.evalGraderScoreModel /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModel, stringCheck, textSimilarity, python, scoreModel) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModelGrader, stringCheckGrader, evalGraderTextSimilarity, evalGraderPython, evalGraderScoreModel) /* spotless:on */ override fun toString(): String = when { - labelModel != null -> "TestingCriterion{labelModel=$labelModel}" - stringCheck != null -> "TestingCriterion{stringCheck=$stringCheck}" - textSimilarity != null -> "TestingCriterion{textSimilarity=$textSimilarity}" - python != null -> "TestingCriterion{python=$python}" - scoreModel != null -> "TestingCriterion{scoreModel=$scoreModel}" + labelModelGrader != null -> "TestingCriterion{labelModelGrader=$labelModelGrader}" + stringCheckGrader != null -> + "TestingCriterion{stringCheckGrader=$stringCheckGrader}" + evalGraderTextSimilarity != null -> + "TestingCriterion{evalGraderTextSimilarity=$evalGraderTextSimilarity}" + evalGraderPython != null -> "TestingCriterion{evalGraderPython=$evalGraderPython}" + evalGraderScoreModel != null -> + "TestingCriterion{evalGraderScoreModel=$evalGraderScoreModel}" _json != null -> "TestingCriterion{_unknown=$_json}" else -> throw IllegalStateException("Invalid TestingCriterion") } @@ -1030,28 +1059,31 @@ private constructor( * evaluation. */ @JvmStatic - fun ofLabelModel(labelModel: EvalLabelModelGrader) = - TestingCriterion(labelModel = labelModel) + fun ofLabelModelGrader(labelModelGrader: LabelModelGrader) = + TestingCriterion(labelModelGrader = labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ @JvmStatic - fun ofStringCheck(stringCheck: EvalStringCheckGrader) = - TestingCriterion(stringCheck = stringCheck) + fun ofStringCheckGrader(stringCheckGrader: StringCheckGrader) = + TestingCriterion(stringCheckGrader = stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ @JvmStatic - fun ofTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - TestingCriterion(textSimilarity = textSimilarity) + fun ofEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity) = + TestingCriterion(evalGraderTextSimilarity = evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - @JvmStatic fun ofPython(python: Python) = TestingCriterion(python = python) + @JvmStatic + fun ofEvalGraderPython(evalGraderPython: EvalGraderPython) = + TestingCriterion(evalGraderPython = evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ @JvmStatic - fun ofScoreModel(scoreModel: ScoreModel) = TestingCriterion(scoreModel = scoreModel) + fun ofEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel) = + TestingCriterion(evalGraderScoreModel = evalGraderScoreModel) } /** @@ -1064,22 +1096,22 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun visitLabelModel(labelModel: EvalLabelModelGrader): T + fun visitLabelModelGrader(labelModelGrader: LabelModelGrader): T /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ - fun visitStringCheck(stringCheck: EvalStringCheckGrader): T + fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader): T /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader): T + fun visitEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity): T /** A PythonGrader object that runs a python script on the input. */ - fun visitPython(python: Python): T + fun visitEvalGraderPython(evalGraderPython: EvalGraderPython): T /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun visitScoreModel(scoreModel: ScoreModel): T + fun visitEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel): T /** * Maps an unknown variant of [TestingCriterion] to a value of type [T]. @@ -1100,37 +1132,38 @@ private constructor( override fun ObjectCodec.deserialize(node: JsonNode): TestingCriterion { val json = JsonValue.fromJsonNode(node) - val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() - when (type) { - "label_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(labelModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "string_check" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(stringCheck = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "text_similarity" -> { - return tryDeserialize(node, jacksonTypeRef()) - ?.let { TestingCriterion(textSimilarity = it, _json = json) } - ?: TestingCriterion(_json = json) - } - "python" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(python = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "score_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(scoreModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(labelModelGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(stringCheckGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderTextSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderPython = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderScoreModel = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> TestingCriterion(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() } - - return TestingCriterion(_json = json) } } @@ -1142,42 +1175,77 @@ private constructor( provider: SerializerProvider, ) { when { - value.labelModel != null -> generator.writeObject(value.labelModel) - value.stringCheck != null -> generator.writeObject(value.stringCheck) - value.textSimilarity != null -> generator.writeObject(value.textSimilarity) - value.python != null -> generator.writeObject(value.python) - value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.labelModelGrader != null -> generator.writeObject(value.labelModelGrader) + value.stringCheckGrader != null -> + generator.writeObject(value.stringCheckGrader) + value.evalGraderTextSimilarity != null -> + generator.writeObject(value.evalGraderTextSimilarity) + value.evalGraderPython != null -> generator.writeObject(value.evalGraderPython) + value.evalGraderScoreModel != null -> + generator.writeObject(value.evalGraderScoreModel) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid TestingCriterion") } } } - /** A PythonGrader object that runs a python script on the input. */ - class Python + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + class EvalGraderTextSimilarity private constructor( + private val evaluationMetric: JsonField, + private val input: JsonField, private val name: JsonField, - private val source: JsonField, + private val reference: JsonField, private val type: JsonValue, - private val imageTag: JsonField, private val passThreshold: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( + @JsonProperty("evaluation_metric") + @ExcludeMissing + evaluationMetric: JsonField = + JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("source") + @JsonProperty("reference") @ExcludeMissing - source: JsonField = JsonMissing.of(), + reference: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - @JsonProperty("image_tag") - @ExcludeMissing - imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) + ) : this(evaluationMetric, input, name, reference, type, passThreshold, mutableMapOf()) + + fun toTextSimilarityGrader(): TextSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(evaluationMetric) + .input(input) + .name(name) + .reference(reference) + .type(type) + .build() + + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun evaluationMetric(): TextSimilarityGrader.EvaluationMetric = + evaluationMetric.getRequired("evaluation_metric") + + /** + * The text being graded. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): String = input.getRequired("input") /** * The name of the grader. @@ -1189,20 +1257,20 @@ private constructor( fun name(): String = name.getRequired("name") /** - * The source code of the python script. + * The text being graded against. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun source(): String = source.getRequired("source") + fun reference(): String = reference.getRequired("reference") /** - * The object type, which is always `python`. + * The type of grader. * * Expected to always return the following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1211,42 +1279,48 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The image tag to use for the python script. + * The threshold for the score. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun imageTag(): Optional = imageTag.getOptional("image_tag") + fun passThreshold(): Double = passThreshold.getRequired("pass_threshold") /** - * The threshold for the score. + * Returns the raw JSON value of [evaluationMetric]. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * Unlike [evaluationMetric], this method doesn't throw if the JSON field has an + * unexpected type. */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + @JsonProperty("evaluation_metric") + @ExcludeMissing + fun _evaluationMetric(): JsonField = + evaluationMetric /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [input]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input /** - * Returns the raw JSON value of [source]. + * Returns the raw JSON value of [name]. * - * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [imageTag]. + * Returns the raw JSON value of [reference]. * - * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * Unlike [reference], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag + @JsonProperty("reference") + @ExcludeMissing + fun _reference(): JsonField = reference /** * Returns the raw JSON value of [passThreshold]. @@ -1273,37 +1347,75 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [Python]. + * Returns a mutable builder for constructing an instance of + * [EvalGraderTextSimilarity]. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [Python]. */ + /** A builder for [EvalGraderTextSimilarity]. */ class Builder internal constructor() { + private var evaluationMetric: JsonField? = + null + private var input: JsonField? = null private var name: JsonField? = null - private var source: JsonField? = null - private var type: JsonValue = JsonValue.from("python") - private var imageTag: JsonField = JsonMissing.of() - private var passThreshold: JsonField = JsonMissing.of() + private var reference: JsonField? = null + private var type: JsonValue = JsonValue.from("text_similarity") + private var passThreshold: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(python: Python) = apply { - name = python.name - source = python.source - type = python.type - imageTag = python.imageTag - passThreshold = python.passThreshold - additionalProperties = python.additionalProperties.toMutableMap() + internal fun from(evalGraderTextSimilarity: EvalGraderTextSimilarity) = apply { + evaluationMetric = evalGraderTextSimilarity.evaluationMetric + input = evalGraderTextSimilarity.input + name = evalGraderTextSimilarity.name + reference = evalGraderTextSimilarity.reference + type = evalGraderTextSimilarity.type + passThreshold = evalGraderTextSimilarity.passThreshold + additionalProperties = + evalGraderTextSimilarity.additionalProperties.toMutableMap() } + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + */ + fun evaluationMetric(evaluationMetric: TextSimilarityGrader.EvaluationMetric) = + evaluationMetric(JsonField.of(evaluationMetric)) + + /** + * Sets [Builder.evaluationMetric] to an arbitrary JSON value. + * + * You should usually call [Builder.evaluationMetric] with a well-typed + * [TextSimilarityGrader.EvaluationMetric] value instead. This method is primarily + * for setting the field to an undocumented or not yet supported value. + */ + fun evaluationMetric( + evaluationMetric: JsonField + ) = apply { this.evaluationMetric = evaluationMetric } + + /** The text being graded. */ + fun input(input: String) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun input(input: JsonField) = apply { this.input = input } + /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1316,17 +1428,17 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } - /** The source code of the python script. */ - fun source(source: String) = source(JsonField.of(source)) + /** The text being graded against. */ + fun reference(reference: String) = reference(JsonField.of(reference)) /** - * Sets [Builder.source] to an arbitrary JSON value. + * Sets [Builder.reference] to an arbitrary JSON value. * - * You should usually call [Builder.source] with a well-typed [String] value + * You should usually call [Builder.reference] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun source(source: JsonField) = apply { this.source = source } + fun reference(reference: JsonField) = apply { this.reference = reference } /** * Sets the field to an arbitrary JSON value. @@ -1334,7 +1446,7 @@ private constructor( * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -1342,18 +1454,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The image tag to use for the python script. */ - fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) - - /** - * Sets [Builder.imageTag] to an arbitrary JSON value. - * - * You should usually call [Builder.imageTag] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } - /** The threshold for the score. */ fun passThreshold(passThreshold: Double) = passThreshold(JsonField.of(passThreshold)) @@ -1392,44 +1492,49 @@ private constructor( } /** - * Returns an immutable instance of [Python]. + * Returns an immutable instance of [EvalGraderTextSimilarity]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): Python = - Python( + fun build(): EvalGraderTextSimilarity = + EvalGraderTextSimilarity( + checkRequired("evaluationMetric", evaluationMetric), + checkRequired("input", input), checkRequired("name", name), - checkRequired("source", source), + checkRequired("reference", reference), type, - imageTag, - passThreshold, + checkRequired("passThreshold", passThreshold), additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): Python = apply { + fun validate(): EvalGraderTextSimilarity = apply { if (validated) { return@apply } + evaluationMetric().validate() + input() name() - source() + reference() _type().let { - if (it != JsonValue.from("python")) { + if (it != JsonValue.from("text_similarity")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - imageTag() passThreshold() validated = true } @@ -1450,10 +1555,11 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (name.asKnown().isPresent) 1 else 0) + - (if (source.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("python")) 1 else 0 } + - (if (imageTag.asKnown().isPresent) 1 else 0) + + (evaluationMetric.asKnown().getOrNull()?.validity() ?: 0) + + (if (input.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (reference.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -1461,84 +1567,77 @@ private constructor( return true } - return /* spotless:off */ other is Python && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderTextSimilarity && evaluationMetric == other.evaluationMetric && input == other.input && name == other.name && reference == other.reference && type == other.type && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, name, reference, type, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Python{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + "EvalGraderTextSimilarity{evaluationMetric=$evaluationMetric, input=$input, name=$name, reference=$reference, type=$type, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } - /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - class ScoreModel + /** A PythonGrader object that runs a python script on the input. */ + class EvalGraderPython private constructor( - private val input: JsonField>, - private val model: JsonField, private val name: JsonField, + private val source: JsonField, private val type: JsonValue, + private val imageTag: JsonField, private val passThreshold: JsonField, - private val range: JsonField>, - private val samplingParams: JsonValue, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("input") - @ExcludeMissing - input: JsonField> = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("source") + @ExcludeMissing + source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("image_tag") + @ExcludeMissing + imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - @JsonProperty("range") - @ExcludeMissing - range: JsonField> = JsonMissing.of(), - @JsonProperty("sampling_params") - @ExcludeMissing - samplingParams: JsonValue = JsonMissing.of(), - ) : this(input, model, name, type, passThreshold, range, samplingParams, mutableMapOf()) + ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) - /** - * The input text. This may include template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun input(): List = input.getRequired("input") + fun toPythonGrader(): PythonGrader = + PythonGrader.builder() + .name(name) + .source(source) + .type(type) + .imageTag(imageTag) + .build() /** - * The model to use for the evaluation. + * The name of the grader. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun model(): String = model.getRequired("model") + fun name(): String = name.getRequired("name") /** - * The name of the grader. + * The source code of the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun name(): String = name.getRequired("name") + fun source(): String = source.getRequired("source") /** - * The object type, which is always `score_model`. + * The object type, which is always `python`. * * Expected to always return the following: * ```java - * JsonValue.from("score_model") + * JsonValue.from("python") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1547,46 +1646,42 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The threshold for the score. + * The image tag to use for the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + fun imageTag(): Optional = imageTag.getOptional("image_tag") /** - * The range of the score. Defaults to `[0, 1]`. + * The threshold for the score. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun range(): Optional> = range.getOptional("range") - - /** The sampling parameters for the model. */ - @JsonProperty("sampling_params") - @ExcludeMissing - fun _samplingParams(): JsonValue = samplingParams + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") /** - * Returns the raw JSON value of [input]. + * Returns the raw JSON value of [name]. * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("input") @ExcludeMissing fun _input(): JsonField> = input + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [model]. + * Returns the raw JSON value of [source]. * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [imageTag]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag /** * Returns the raw JSON value of [passThreshold]. @@ -1598,13 +1693,6 @@ private constructor( @ExcludeMissing fun _passThreshold(): JsonField = passThreshold - /** - * Returns the raw JSON value of [range]. - * - * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1620,80 +1708,37 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [ScoreModel]. + * Returns a mutable builder for constructing an instance of [EvalGraderPython]. * * The following fields are required: * ```java - * .input() - * .model() * .name() + * .source() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [ScoreModel]. */ + /** A builder for [EvalGraderPython]. */ class Builder internal constructor() { - private var input: JsonField>? = null - private var model: JsonField? = null private var name: JsonField? = null - private var type: JsonValue = JsonValue.from("score_model") + private var source: JsonField? = null + private var type: JsonValue = JsonValue.from("python") + private var imageTag: JsonField = JsonMissing.of() private var passThreshold: JsonField = JsonMissing.of() - private var range: JsonField>? = null - private var samplingParams: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(scoreModel: ScoreModel) = apply { - input = scoreModel.input.map { it.toMutableList() } - model = scoreModel.model - name = scoreModel.name - type = scoreModel.type - passThreshold = scoreModel.passThreshold - range = scoreModel.range.map { it.toMutableList() } - samplingParams = scoreModel.samplingParams - additionalProperties = scoreModel.additionalProperties.toMutableMap() - } - - /** The input text. This may include template strings. */ - fun input(input: List) = input(JsonField.of(input)) - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun input(input: JsonField>) = apply { - this.input = input.map { it.toMutableList() } - } - - /** - * Adds a single [Input] to [Builder.input]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addInput(input: Input) = apply { - this.input = - (this.input ?: JsonField.of(mutableListOf())).also { - checkKnown("input", it).add(input) - } + internal fun from(evalGraderPython: EvalGraderPython) = apply { + name = evalGraderPython.name + source = evalGraderPython.source + type = evalGraderPython.type + imageTag = evalGraderPython.imageTag + passThreshold = evalGraderPython.passThreshold + additionalProperties = evalGraderPython.additionalProperties.toMutableMap() } - /** The model to use for the evaluation. */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1706,8 +1751,410 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** The source code of the python script. */ + fun source(source: String) = source(JsonField.of(source)) + /** - * Sets the field to an arbitrary JSON value. + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("python") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The image tag to use for the python script. */ + fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) + + /** + * Sets [Builder.imageTag] to an arbitrary JSON value. + * + * You should usually call [Builder.imageTag] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } + + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [EvalGraderPython]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .source() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EvalGraderPython = + EvalGraderPython( + checkRequired("name", name), + checkRequired("source", source), + type, + imageTag, + passThreshold, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): EvalGraderPython = apply { + if (validated) { + return@apply + } + + name() + source() + _type().let { + if (it != JsonValue.from("python")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + imageTag() + passThreshold() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (if (source.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("python")) 1 else 0 } + + (if (imageTag.asKnown().isPresent) 1 else 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is EvalGraderPython && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "EvalGraderPython{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + } + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + class EvalGraderScoreModel + private constructor( + private val input: JsonField>, + private val model: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val range: JsonField>, + private val samplingParams: JsonValue, + private val passThreshold: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("input") + @ExcludeMissing + input: JsonField> = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("range") + @ExcludeMissing + range: JsonField> = JsonMissing.of(), + @JsonProperty("sampling_params") + @ExcludeMissing + samplingParams: JsonValue = JsonMissing.of(), + @JsonProperty("pass_threshold") + @ExcludeMissing + passThreshold: JsonField = JsonMissing.of(), + ) : this(input, model, name, type, range, samplingParams, passThreshold, mutableMapOf()) + + fun toScoreModelGrader(): ScoreModelGrader = + ScoreModelGrader.builder() + .input(input) + .model(model) + .name(name) + .type(type) + .range(range) + .samplingParams(samplingParams) + .build() + + /** + * The input text. This may include template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): List = input.getRequired("input") + + /** + * The model to use for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun model(): String = model.getRequired("model") + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") + + /** + * The object type, which is always `score_model`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The range of the score. Defaults to `[0, 1]`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun range(): Optional> = range.getOptional("range") + + /** The sampling parameters for the model. */ + @JsonProperty("sampling_params") + @ExcludeMissing + fun _samplingParams(): JsonValue = samplingParams + + /** + * The threshold for the score. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") + @ExcludeMissing + fun _input(): JsonField> = input + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [range]. + * + * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range + + /** + * Returns the raw JSON value of [passThreshold]. + * + * Unlike [passThreshold], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pass_threshold") + @ExcludeMissing + fun _passThreshold(): JsonField = passThreshold + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [EvalGraderScoreModel]. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [EvalGraderScoreModel]. */ + class Builder internal constructor() { + + private var input: JsonField>? = null + private var model: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("score_model") + private var range: JsonField>? = null + private var samplingParams: JsonValue = JsonMissing.of() + private var passThreshold: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(evalGraderScoreModel: EvalGraderScoreModel) = apply { + input = evalGraderScoreModel.input.map { it.toMutableList() } + model = evalGraderScoreModel.model + name = evalGraderScoreModel.name + type = evalGraderScoreModel.type + range = evalGraderScoreModel.range.map { it.toMutableList() } + samplingParams = evalGraderScoreModel.samplingParams + passThreshold = evalGraderScoreModel.passThreshold + additionalProperties = evalGraderScoreModel.additionalProperties.toMutableMap() + } + + /** The input text. This may include template strings. */ + fun input(input: List) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField>) = apply { + this.input = input.map { it.toMutableList() } + } + + /** + * Adds a single [ScoreModelGrader.Input] to [Builder.input]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addInput(input: ScoreModelGrader.Input) = apply { + this.input = + (this.input ?: JsonField.of(mutableListOf())).also { + checkKnown("input", it).add(input) + } + } + + /** The model to use for the evaluation. */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Sets the field to an arbitrary JSON value. * * It is usually unnecessary to call this method because the field defaults to the * following: @@ -1720,21 +2167,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The threshold for the score. */ - fun passThreshold(passThreshold: Double) = - passThreshold(JsonField.of(passThreshold)) - - /** - * Sets [Builder.passThreshold] to an arbitrary JSON value. - * - * You should usually call [Builder.passThreshold] with a well-typed [Double] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun passThreshold(passThreshold: JsonField) = apply { - this.passThreshold = passThreshold - } - /** The range of the score. Defaults to `[0, 1]`. */ fun range(range: List) = range(JsonField.of(range)) @@ -1766,6 +2198,21 @@ private constructor( this.samplingParams = samplingParams } + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1789,7 +2236,7 @@ private constructor( } /** - * Returns an immutable instance of [ScoreModel]. + * Returns an immutable instance of [EvalGraderScoreModel]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -1802,22 +2249,22 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): ScoreModel = - ScoreModel( + fun build(): EvalGraderScoreModel = + EvalGraderScoreModel( checkRequired("input", input).map { it.toImmutable() }, checkRequired("model", model), checkRequired("name", name), type, - passThreshold, (range ?: JsonMissing.of()).map { it.toImmutable() }, samplingParams, + passThreshold, additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): ScoreModel = apply { + fun validate(): EvalGraderScoreModel = apply { if (validated) { return@apply } @@ -1830,8 +2277,8 @@ private constructor( throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - passThreshold() range() + passThreshold() validated = true } @@ -1855,1003 +2302,25 @@ private constructor( (if (model.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + - (if (passThreshold.asKnown().isPresent) 1 else 0) + - (range.asKnown().getOrNull()?.size ?: 0) - - /** - * A message input to the model with a role indicating instruction following hierarchy. - * Instructions given with the `developer` or `system` role take precedence over - * instructions given with the `user` role. Messages with the `assistant` role are - * presumed to have been generated by the model in previous interactions. - */ - class Input - private constructor( - private val content: JsonField, - private val role: JsonField, - private val type: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("content") - @ExcludeMissing - content: JsonField = JsonMissing.of(), - @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(content, role, type, mutableMapOf()) - - /** - * Text inputs to the model - can contain template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun content(): Content = content.getRequired("content") - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun role(): Role = role.getRequired("role") - - /** - * The type of the message input. Always `message`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") - - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("content") - @ExcludeMissing - fun _content(): JsonField = content - - /** - * Returns the raw JSON value of [role]. - * - * Unlike [role], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Input]. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Input]. */ - class Builder internal constructor() { - - private var content: JsonField? = null - private var role: JsonField? = null - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(input: Input) = apply { - content = input.content - role = input.role - type = input.type - additionalProperties = input.additionalProperties.toMutableMap() - } - - /** Text inputs to the model - can contain template strings. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - - /** Alias for calling [content] with `Content.ofTextInput(textInput)`. */ - fun content(textInput: String) = content(Content.ofTextInput(textInput)) - - /** - * Alias for calling [content] with - * `Content.ofResponseInputText(responseInputText)`. - */ - fun content(responseInputText: ResponseInputText) = - content(Content.ofResponseInputText(responseInputText)) - - /** Alias for calling [content] with `Content.ofOutputText(outputText)`. */ - fun content(outputText: Content.OutputText) = - content(Content.ofOutputText(outputText)) - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - fun role(role: Role) = role(JsonField.of(role)) - - /** - * Sets [Builder.role] to an arbitrary JSON value. - * - * You should usually call [Builder.role] with a well-typed [Role] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun role(role: JsonField) = apply { this.role = role } - - /** The type of the message input. Always `message`. */ - fun type(type: Type) = type(JsonField.of(type)) - - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Input]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Input = - Input( - checkRequired("content", content), - checkRequired("role", role), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Input = apply { - if (validated) { - return@apply - } - - content().validate() - role().validate() - type().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (content.asKnown().getOrNull()?.validity() ?: 0) + - (role.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) - - /** Text inputs to the model - can contain template strings. */ - @JsonDeserialize(using = Content.Deserializer::class) - @JsonSerialize(using = Content.Serializer::class) - class Content - private constructor( - private val textInput: String? = null, - private val responseInputText: ResponseInputText? = null, - private val outputText: OutputText? = null, - private val _json: JsonValue? = null, - ) { - - /** A text input to the model. */ - fun textInput(): Optional = Optional.ofNullable(textInput) - - /** A text input to the model. */ - fun responseInputText(): Optional = - Optional.ofNullable(responseInputText) - - /** A text output from the model. */ - fun outputText(): Optional = Optional.ofNullable(outputText) - - fun isTextInput(): Boolean = textInput != null - - fun isResponseInputText(): Boolean = responseInputText != null - - fun isOutputText(): Boolean = outputText != null - - /** A text input to the model. */ - fun asTextInput(): String = textInput.getOrThrow("textInput") - - /** A text input to the model. */ - fun asResponseInputText(): ResponseInputText = - responseInputText.getOrThrow("responseInputText") - - /** A text output from the model. */ - fun asOutputText(): OutputText = outputText.getOrThrow("outputText") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - textInput != null -> visitor.visitTextInput(textInput) - responseInputText != null -> - visitor.visitResponseInputText(responseInputText) - outputText != null -> visitor.visitOutputText(outputText) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Content = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitTextInput(textInput: String) {} - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) { - responseInputText.validate() - } - - override fun visitOutputText(outputText: OutputText) { - outputText.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitTextInput(textInput: String) = 1 - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) = responseInputText.validity() - - override fun visitOutputText(outputText: OutputText) = - outputText.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && textInput == other.textInput && responseInputText == other.responseInputText && outputText == other.outputText /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(textInput, responseInputText, outputText) /* spotless:on */ - - override fun toString(): String = - when { - textInput != null -> "Content{textInput=$textInput}" - responseInputText != null -> - "Content{responseInputText=$responseInputText}" - outputText != null -> "Content{outputText=$outputText}" - _json != null -> "Content{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Content") - } - - companion object { - - /** A text input to the model. */ - @JvmStatic - fun ofTextInput(textInput: String) = Content(textInput = textInput) - - /** A text input to the model. */ - @JvmStatic - fun ofResponseInputText(responseInputText: ResponseInputText) = - Content(responseInputText = responseInputText) - - /** A text output from the model. */ - @JvmStatic - fun ofOutputText(outputText: OutputText) = Content(outputText = outputText) - } - - /** - * An interface that defines how to map each variant of [Content] to a value of - * type [T]. - */ - interface Visitor { - - /** A text input to the model. */ - fun visitTextInput(textInput: String): T - - /** A text input to the model. */ - fun visitResponseInputText(responseInputText: ResponseInputText): T - - /** A text output from the model. */ - fun visitOutputText(outputText: OutputText): T - - /** - * Maps an unknown variant of [Content] to a value of type [T]. - * - * An instance of [Content] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Content: $json") - } - } - - internal class Deserializer : BaseDeserializer(Content::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Content { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Content(responseInputText = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(outputText = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(textInput = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from array). - 0 -> Content(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Content::class) { - - override fun serialize( - value: Content, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.textInput != null -> generator.writeObject(value.textInput) - value.responseInputText != null -> - generator.writeObject(value.responseInputText) - value.outputText != null -> generator.writeObject(value.outputText) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Content") - } - } - } - - /** A text output from the model. */ - class OutputText - private constructor( - private val text: JsonField, - private val type: JsonValue, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("text") - @ExcludeMissing - text: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - ) : this(text, type, mutableMapOf()) - - /** - * The text output from the model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded - * with an unexpected value). - */ - fun text(): String = text.getRequired("text") - - /** - * The type of the output text. Always `output_text`. - * - * Expected to always return the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * However, this method can be useful for debugging and logging (e.g. if the - * server responded with an unexpected value). - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - - /** - * Returns the raw JSON value of [text]. - * - * Unlike [text], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [OutputText]. - * - * The following fields are required: - * ```java - * .text() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [OutputText]. */ - class Builder internal constructor() { - - private var text: JsonField? = null - private var type: JsonValue = JsonValue.from("output_text") - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(outputText: OutputText) = apply { - text = outputText.text - type = outputText.type - additionalProperties = - outputText.additionalProperties.toMutableMap() - } - - /** The text output from the model. */ - fun text(text: String) = text(JsonField.of(text)) - - /** - * Sets [Builder.text] to an arbitrary JSON value. - * - * You should usually call [Builder.text] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun text(text: JsonField) = apply { this.text = text } - - /** - * Sets the field to an arbitrary JSON value. - * - * It is usually unnecessary to call this method because the field - * defaults to the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonValue) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [OutputText]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - * - * The following fields are required: - * ```java - * .text() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): OutputText = - OutputText( - checkRequired("text", text), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): OutputText = apply { - if (validated) { - return@apply - } - - text() - _type().let { - if (it != JsonValue.from("output_text")) { - throw OpenAIInvalidDataException( - "'type' is invalid, received $it" - ) - } - } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (text.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("output_text")) 1 else 0 } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is OutputText && text == other.text && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(text, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "OutputText{text=$text, type=$type, additionalProperties=$additionalProperties}" - } - } - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - class Role @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val USER = of("user") - - @JvmField val ASSISTANT = of("assistant") - - @JvmField val SYSTEM = of("system") - - @JvmField val DEVELOPER = of("developer") - - @JvmStatic fun of(value: String) = Role(JsonField.of(value)) - } - - /** An enum containing [Role]'s known values. */ - enum class Known { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - } - - /** - * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Role] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - /** - * An enum member indicating that [Role] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - USER -> Value.USER - ASSISTANT -> Value.ASSISTANT - SYSTEM -> Value.SYSTEM - DEVELOPER -> Value.DEVELOPER - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - USER -> Known.USER - ASSISTANT -> Known.ASSISTANT - SYSTEM -> Known.SYSTEM - DEVELOPER -> Known.DEVELOPER - else -> throw OpenAIInvalidDataException("Unknown Role: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Role = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Role && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - /** The type of the message input. Always `message`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val MESSAGE = of("message") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - MESSAGE - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - MESSAGE, - /** - * An enum member indicating that [Type] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - MESSAGE -> Value.MESSAGE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - MESSAGE -> Known.MESSAGE - else -> throw OpenAIInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Type && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Input && content == other.content && role == other.role && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(content, role, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Input{content=$content, role=$role, type=$type, additionalProperties=$additionalProperties}" - } + (range.asKnown().getOrNull()?.size ?: 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && passThreshold == other.passThreshold && range == other.range && samplingParams == other.samplingParams && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && range == other.range && samplingParams == other.samplingParams && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(input, model, name, type, passThreshold, range, samplingParams, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(input, model, name, type, range, samplingParams, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "ScoreModel{input=$input, model=$model, name=$name, type=$type, passThreshold=$passThreshold, range=$range, samplingParams=$samplingParams, additionalProperties=$additionalProperties}" + "EvalGraderScoreModel{input=$input, model=$model, name=$name, type=$type, range=$range, samplingParams=$samplingParams, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalDeleteParams.kt index 7220bde2a..74f97a4ee 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalDeleteParams.kt @@ -4,23 +4,23 @@ package com.openai.models.evals import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Delete an evaluation. */ class EvalDeleteParams private constructor( - private val evalId: String, + private val evalId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun evalId(): String = evalId + fun evalId(): Optional = Optional.ofNullable(evalId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [EvalDeleteParams]. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - */ + @JvmStatic fun none(): EvalDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [EvalDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,7 +54,10 @@ private constructor( additionalBodyProperties = evalDeleteParams.additionalBodyProperties.toMutableMap() } - fun evalId(evalId: String) = apply { this.evalId = evalId } + fun evalId(evalId: String?) = apply { this.evalId = evalId } + + /** Alias for calling [Builder.evalId] with `evalId.orElse(null)`. */ + fun evalId(evalId: Optional) = evalId(evalId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -185,17 +183,10 @@ private constructor( * Returns an immutable instance of [EvalDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): EvalDeleteParams = EvalDeleteParams( - checkRequired("evalId", evalId), + evalId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -207,7 +198,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> evalId + 0 -> evalId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPage.kt index aa65e3f97..38d95a847 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.evals +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.EvalService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [EvalService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: EvalService, private val params: EvalListParams, private val response: EvalListPageResponse, -) { +) : Page { /** * Delegates to [EvalListPageResponse], but gracefully handles missing data. @@ -33,19 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): EvalListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): EvalListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): EvalListParams = params @@ -114,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: EvalListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPageAsync.kt index d23299f44..c98e16f52 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.evals +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.EvalServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [EvalServiceAsync.list] */ class EvalListPageAsync private constructor( private val service: EvalServiceAsync, + private val streamHandlerExecutor: Executor, private val params: EvalListParams, private val response: EvalListPageResponse, -) { +) : PageAsync { /** * Delegates to [EvalListPageResponse], but gracefully handles missing data. @@ -34,22 +36,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): EvalListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): EvalListParams = params @@ -67,6 +64,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +76,24 @@ private constructor( class Builder internal constructor() { private var service: EvalServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: EvalListParams? = null private var response: EvalListPageResponse? = null @JvmSynthetic internal fun from(evalListPageAsync: EvalListPageAsync) = apply { service = evalListPageAsync.service + streamHandlerExecutor = evalListPageAsync.streamHandlerExecutor params = evalListPageAsync.params response = evalListPageAsync.response } fun service(service: EvalServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: EvalListParams) = apply { this.params = params } @@ -104,6 +108,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +118,22 @@ private constructor( fun build(): EvalListPageAsync = EvalListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: EvalListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (EvalListResponse) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is EvalListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is EvalListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "EvalListPageAsync{service=$service, params=$params, response=$response}" + "EvalListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListResponse.kt index 2d3a7b7d1..e10091075 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListResponse.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalListResponse.kt @@ -15,7 +15,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.BaseDeserializer import com.openai.core.BaseSerializer -import com.openai.core.Enum import com.openai.core.ExcludeMissing import com.openai.core.JsonField import com.openai.core.JsonMissing @@ -26,7 +25,11 @@ import com.openai.core.checkRequired import com.openai.core.getOrThrow import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException -import com.openai.models.responses.ResponseInputText +import com.openai.models.graders.gradermodels.LabelModelGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader import java.util.Collections import java.util.Objects import java.util.Optional @@ -388,34 +391,43 @@ private constructor( } /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofLabelModel(labelModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofLabelModelGrader(labelModelGrader)`. */ - fun addTestingCriterion(labelModel: EvalLabelModelGrader) = - addTestingCriterion(TestingCriterion.ofLabelModel(labelModel)) + fun addTestingCriterion(labelModelGrader: LabelModelGrader) = + addTestingCriterion(TestingCriterion.ofLabelModelGrader(labelModelGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofStringCheck(stringCheck)`. + * `TestingCriterion.ofStringCheckGrader(stringCheckGrader)`. */ - fun addTestingCriterion(stringCheck: EvalStringCheckGrader) = - addTestingCriterion(TestingCriterion.ofStringCheck(stringCheck)) + fun addTestingCriterion(stringCheckGrader: StringCheckGrader) = + addTestingCriterion(TestingCriterion.ofStringCheckGrader(stringCheckGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofTextSimilarity(textSimilarity)`. + * `TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity)`. */ - fun addTestingCriterion(textSimilarity: EvalTextSimilarityGrader) = - addTestingCriterion(TestingCriterion.ofTextSimilarity(textSimilarity)) + fun addTestingCriterion( + evalGraderTextSimilarity: TestingCriterion.EvalGraderTextSimilarity + ) = + addTestingCriterion( + TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity) + ) - /** Alias for calling [addTestingCriterion] with `TestingCriterion.ofPython(python)`. */ - fun addTestingCriterion(python: TestingCriterion.Python) = - addTestingCriterion(TestingCriterion.ofPython(python)) + /** + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderPython(evalGraderPython)`. + */ + fun addTestingCriterion(evalGraderPython: TestingCriterion.EvalGraderPython) = + addTestingCriterion(TestingCriterion.ofEvalGraderPython(evalGraderPython)) /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofScoreModel(scoreModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)`. */ - fun addTestingCriterion(scoreModel: TestingCriterion.ScoreModel) = - addTestingCriterion(TestingCriterion.ofScoreModel(scoreModel)) + fun addTestingCriterion(evalGraderScoreModel: TestingCriterion.EvalGraderScoreModel) = + addTestingCriterion(TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)) fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -860,11 +872,11 @@ private constructor( @JsonSerialize(using = TestingCriterion.Serializer::class) class TestingCriterion private constructor( - private val labelModel: EvalLabelModelGrader? = null, - private val stringCheck: EvalStringCheckGrader? = null, - private val textSimilarity: EvalTextSimilarityGrader? = null, - private val python: Python? = null, - private val scoreModel: ScoreModel? = null, + private val labelModelGrader: LabelModelGrader? = null, + private val stringCheckGrader: StringCheckGrader? = null, + private val evalGraderTextSimilarity: EvalGraderTextSimilarity? = null, + private val evalGraderPython: EvalGraderPython? = null, + private val evalGraderScoreModel: EvalGraderScoreModel? = null, private val _json: JsonValue? = null, ) { @@ -872,65 +884,71 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun labelModel(): Optional = Optional.ofNullable(labelModel) + fun labelModelGrader(): Optional = Optional.ofNullable(labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + fun stringCheckGrader(): Optional = + Optional.ofNullable(stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun textSimilarity(): Optional = - Optional.ofNullable(textSimilarity) + fun evalGraderTextSimilarity(): Optional = + Optional.ofNullable(evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - fun python(): Optional = Optional.ofNullable(python) + fun evalGraderPython(): Optional = Optional.ofNullable(evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + fun evalGraderScoreModel(): Optional = + Optional.ofNullable(evalGraderScoreModel) - fun isLabelModel(): Boolean = labelModel != null + fun isLabelModelGrader(): Boolean = labelModelGrader != null - fun isStringCheck(): Boolean = stringCheck != null + fun isStringCheckGrader(): Boolean = stringCheckGrader != null - fun isTextSimilarity(): Boolean = textSimilarity != null + fun isEvalGraderTextSimilarity(): Boolean = evalGraderTextSimilarity != null - fun isPython(): Boolean = python != null + fun isEvalGraderPython(): Boolean = evalGraderPython != null - fun isScoreModel(): Boolean = scoreModel != null + fun isEvalGraderScoreModel(): Boolean = evalGraderScoreModel != null /** * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun asLabelModel(): EvalLabelModelGrader = labelModel.getOrThrow("labelModel") + fun asLabelModelGrader(): LabelModelGrader = labelModelGrader.getOrThrow("labelModelGrader") /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun asStringCheck(): EvalStringCheckGrader = stringCheck.getOrThrow("stringCheck") + fun asStringCheckGrader(): StringCheckGrader = + stringCheckGrader.getOrThrow("stringCheckGrader") /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun asTextSimilarity(): EvalTextSimilarityGrader = - textSimilarity.getOrThrow("textSimilarity") + fun asEvalGraderTextSimilarity(): EvalGraderTextSimilarity = + evalGraderTextSimilarity.getOrThrow("evalGraderTextSimilarity") /** A PythonGrader object that runs a python script on the input. */ - fun asPython(): Python = python.getOrThrow("python") + fun asEvalGraderPython(): EvalGraderPython = evalGraderPython.getOrThrow("evalGraderPython") /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun asScoreModel(): ScoreModel = scoreModel.getOrThrow("scoreModel") + fun asEvalGraderScoreModel(): EvalGraderScoreModel = + evalGraderScoreModel.getOrThrow("evalGraderScoreModel") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { - labelModel != null -> visitor.visitLabelModel(labelModel) - stringCheck != null -> visitor.visitStringCheck(stringCheck) - textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) - python != null -> visitor.visitPython(python) - scoreModel != null -> visitor.visitScoreModel(scoreModel) + labelModelGrader != null -> visitor.visitLabelModelGrader(labelModelGrader) + stringCheckGrader != null -> visitor.visitStringCheckGrader(stringCheckGrader) + evalGraderTextSimilarity != null -> + visitor.visitEvalGraderTextSimilarity(evalGraderTextSimilarity) + evalGraderPython != null -> visitor.visitEvalGraderPython(evalGraderPython) + evalGraderScoreModel != null -> + visitor.visitEvalGraderScoreModel(evalGraderScoreModel) else -> visitor.unknown(_json) } @@ -943,24 +961,28 @@ private constructor( accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) { - labelModel.validate() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) { + labelModelGrader.validate() } - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) { - stringCheck.validate() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) { + stringCheckGrader.validate() } - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) { - textSimilarity.validate() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) { + evalGraderTextSimilarity.validate() } - override fun visitPython(python: Python) { - python.validate() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) { + evalGraderPython.validate() } - override fun visitScoreModel(scoreModel: ScoreModel) { - scoreModel.validate() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) { + evalGraderScoreModel.validate() } } ) @@ -985,18 +1007,22 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) = - labelModel.validity() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) = + labelModelGrader.validity() - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) = - stringCheck.validity() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) = + stringCheckGrader.validity() - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - textSimilarity.validity() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) = evalGraderTextSimilarity.validity() - override fun visitPython(python: Python) = python.validity() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) = + evalGraderPython.validity() - override fun visitScoreModel(scoreModel: ScoreModel) = scoreModel.validity() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) = evalGraderScoreModel.validity() override fun unknown(json: JsonValue?) = 0 } @@ -1007,18 +1033,21 @@ private constructor( return true } - return /* spotless:off */ other is TestingCriterion && labelModel == other.labelModel && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel /* spotless:on */ + return /* spotless:off */ other is TestingCriterion && labelModelGrader == other.labelModelGrader && stringCheckGrader == other.stringCheckGrader && evalGraderTextSimilarity == other.evalGraderTextSimilarity && evalGraderPython == other.evalGraderPython && evalGraderScoreModel == other.evalGraderScoreModel /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModel, stringCheck, textSimilarity, python, scoreModel) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModelGrader, stringCheckGrader, evalGraderTextSimilarity, evalGraderPython, evalGraderScoreModel) /* spotless:on */ override fun toString(): String = when { - labelModel != null -> "TestingCriterion{labelModel=$labelModel}" - stringCheck != null -> "TestingCriterion{stringCheck=$stringCheck}" - textSimilarity != null -> "TestingCriterion{textSimilarity=$textSimilarity}" - python != null -> "TestingCriterion{python=$python}" - scoreModel != null -> "TestingCriterion{scoreModel=$scoreModel}" + labelModelGrader != null -> "TestingCriterion{labelModelGrader=$labelModelGrader}" + stringCheckGrader != null -> + "TestingCriterion{stringCheckGrader=$stringCheckGrader}" + evalGraderTextSimilarity != null -> + "TestingCriterion{evalGraderTextSimilarity=$evalGraderTextSimilarity}" + evalGraderPython != null -> "TestingCriterion{evalGraderPython=$evalGraderPython}" + evalGraderScoreModel != null -> + "TestingCriterion{evalGraderScoreModel=$evalGraderScoreModel}" _json != null -> "TestingCriterion{_unknown=$_json}" else -> throw IllegalStateException("Invalid TestingCriterion") } @@ -1030,28 +1059,31 @@ private constructor( * evaluation. */ @JvmStatic - fun ofLabelModel(labelModel: EvalLabelModelGrader) = - TestingCriterion(labelModel = labelModel) + fun ofLabelModelGrader(labelModelGrader: LabelModelGrader) = + TestingCriterion(labelModelGrader = labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ @JvmStatic - fun ofStringCheck(stringCheck: EvalStringCheckGrader) = - TestingCriterion(stringCheck = stringCheck) + fun ofStringCheckGrader(stringCheckGrader: StringCheckGrader) = + TestingCriterion(stringCheckGrader = stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ @JvmStatic - fun ofTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - TestingCriterion(textSimilarity = textSimilarity) + fun ofEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity) = + TestingCriterion(evalGraderTextSimilarity = evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - @JvmStatic fun ofPython(python: Python) = TestingCriterion(python = python) + @JvmStatic + fun ofEvalGraderPython(evalGraderPython: EvalGraderPython) = + TestingCriterion(evalGraderPython = evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ @JvmStatic - fun ofScoreModel(scoreModel: ScoreModel) = TestingCriterion(scoreModel = scoreModel) + fun ofEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel) = + TestingCriterion(evalGraderScoreModel = evalGraderScoreModel) } /** @@ -1064,22 +1096,22 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun visitLabelModel(labelModel: EvalLabelModelGrader): T + fun visitLabelModelGrader(labelModelGrader: LabelModelGrader): T /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ - fun visitStringCheck(stringCheck: EvalStringCheckGrader): T + fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader): T /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader): T + fun visitEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity): T /** A PythonGrader object that runs a python script on the input. */ - fun visitPython(python: Python): T + fun visitEvalGraderPython(evalGraderPython: EvalGraderPython): T /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun visitScoreModel(scoreModel: ScoreModel): T + fun visitEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel): T /** * Maps an unknown variant of [TestingCriterion] to a value of type [T]. @@ -1100,37 +1132,38 @@ private constructor( override fun ObjectCodec.deserialize(node: JsonNode): TestingCriterion { val json = JsonValue.fromJsonNode(node) - val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() - when (type) { - "label_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(labelModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "string_check" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(stringCheck = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "text_similarity" -> { - return tryDeserialize(node, jacksonTypeRef()) - ?.let { TestingCriterion(textSimilarity = it, _json = json) } - ?: TestingCriterion(_json = json) - } - "python" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(python = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "score_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(scoreModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(labelModelGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(stringCheckGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderTextSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderPython = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderScoreModel = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> TestingCriterion(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() } - - return TestingCriterion(_json = json) } } @@ -1142,42 +1175,77 @@ private constructor( provider: SerializerProvider, ) { when { - value.labelModel != null -> generator.writeObject(value.labelModel) - value.stringCheck != null -> generator.writeObject(value.stringCheck) - value.textSimilarity != null -> generator.writeObject(value.textSimilarity) - value.python != null -> generator.writeObject(value.python) - value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.labelModelGrader != null -> generator.writeObject(value.labelModelGrader) + value.stringCheckGrader != null -> + generator.writeObject(value.stringCheckGrader) + value.evalGraderTextSimilarity != null -> + generator.writeObject(value.evalGraderTextSimilarity) + value.evalGraderPython != null -> generator.writeObject(value.evalGraderPython) + value.evalGraderScoreModel != null -> + generator.writeObject(value.evalGraderScoreModel) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid TestingCriterion") } } } - /** A PythonGrader object that runs a python script on the input. */ - class Python + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + class EvalGraderTextSimilarity private constructor( + private val evaluationMetric: JsonField, + private val input: JsonField, private val name: JsonField, - private val source: JsonField, + private val reference: JsonField, private val type: JsonValue, - private val imageTag: JsonField, private val passThreshold: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( + @JsonProperty("evaluation_metric") + @ExcludeMissing + evaluationMetric: JsonField = + JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("source") + @JsonProperty("reference") @ExcludeMissing - source: JsonField = JsonMissing.of(), + reference: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - @JsonProperty("image_tag") - @ExcludeMissing - imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) + ) : this(evaluationMetric, input, name, reference, type, passThreshold, mutableMapOf()) + + fun toTextSimilarityGrader(): TextSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(evaluationMetric) + .input(input) + .name(name) + .reference(reference) + .type(type) + .build() + + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun evaluationMetric(): TextSimilarityGrader.EvaluationMetric = + evaluationMetric.getRequired("evaluation_metric") + + /** + * The text being graded. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): String = input.getRequired("input") /** * The name of the grader. @@ -1189,20 +1257,20 @@ private constructor( fun name(): String = name.getRequired("name") /** - * The source code of the python script. + * The text being graded against. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun source(): String = source.getRequired("source") + fun reference(): String = reference.getRequired("reference") /** - * The object type, which is always `python`. + * The type of grader. * * Expected to always return the following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1211,42 +1279,48 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The image tag to use for the python script. + * The threshold for the score. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun imageTag(): Optional = imageTag.getOptional("image_tag") + fun passThreshold(): Double = passThreshold.getRequired("pass_threshold") /** - * The threshold for the score. + * Returns the raw JSON value of [evaluationMetric]. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * Unlike [evaluationMetric], this method doesn't throw if the JSON field has an + * unexpected type. */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + @JsonProperty("evaluation_metric") + @ExcludeMissing + fun _evaluationMetric(): JsonField = + evaluationMetric /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [input]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input /** - * Returns the raw JSON value of [source]. + * Returns the raw JSON value of [name]. * - * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [imageTag]. + * Returns the raw JSON value of [reference]. * - * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * Unlike [reference], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag + @JsonProperty("reference") + @ExcludeMissing + fun _reference(): JsonField = reference /** * Returns the raw JSON value of [passThreshold]. @@ -1273,37 +1347,75 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [Python]. + * Returns a mutable builder for constructing an instance of + * [EvalGraderTextSimilarity]. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [Python]. */ + /** A builder for [EvalGraderTextSimilarity]. */ class Builder internal constructor() { + private var evaluationMetric: JsonField? = + null + private var input: JsonField? = null private var name: JsonField? = null - private var source: JsonField? = null - private var type: JsonValue = JsonValue.from("python") - private var imageTag: JsonField = JsonMissing.of() - private var passThreshold: JsonField = JsonMissing.of() + private var reference: JsonField? = null + private var type: JsonValue = JsonValue.from("text_similarity") + private var passThreshold: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(python: Python) = apply { - name = python.name - source = python.source - type = python.type - imageTag = python.imageTag - passThreshold = python.passThreshold - additionalProperties = python.additionalProperties.toMutableMap() + internal fun from(evalGraderTextSimilarity: EvalGraderTextSimilarity) = apply { + evaluationMetric = evalGraderTextSimilarity.evaluationMetric + input = evalGraderTextSimilarity.input + name = evalGraderTextSimilarity.name + reference = evalGraderTextSimilarity.reference + type = evalGraderTextSimilarity.type + passThreshold = evalGraderTextSimilarity.passThreshold + additionalProperties = + evalGraderTextSimilarity.additionalProperties.toMutableMap() } + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + */ + fun evaluationMetric(evaluationMetric: TextSimilarityGrader.EvaluationMetric) = + evaluationMetric(JsonField.of(evaluationMetric)) + + /** + * Sets [Builder.evaluationMetric] to an arbitrary JSON value. + * + * You should usually call [Builder.evaluationMetric] with a well-typed + * [TextSimilarityGrader.EvaluationMetric] value instead. This method is primarily + * for setting the field to an undocumented or not yet supported value. + */ + fun evaluationMetric( + evaluationMetric: JsonField + ) = apply { this.evaluationMetric = evaluationMetric } + + /** The text being graded. */ + fun input(input: String) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun input(input: JsonField) = apply { this.input = input } + /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1316,17 +1428,17 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } - /** The source code of the python script. */ - fun source(source: String) = source(JsonField.of(source)) + /** The text being graded against. */ + fun reference(reference: String) = reference(JsonField.of(reference)) /** - * Sets [Builder.source] to an arbitrary JSON value. + * Sets [Builder.reference] to an arbitrary JSON value. * - * You should usually call [Builder.source] with a well-typed [String] value + * You should usually call [Builder.reference] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun source(source: JsonField) = apply { this.source = source } + fun reference(reference: JsonField) = apply { this.reference = reference } /** * Sets the field to an arbitrary JSON value. @@ -1334,7 +1446,7 @@ private constructor( * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -1342,18 +1454,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The image tag to use for the python script. */ - fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) - - /** - * Sets [Builder.imageTag] to an arbitrary JSON value. - * - * You should usually call [Builder.imageTag] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } - /** The threshold for the score. */ fun passThreshold(passThreshold: Double) = passThreshold(JsonField.of(passThreshold)) @@ -1392,44 +1492,49 @@ private constructor( } /** - * Returns an immutable instance of [Python]. + * Returns an immutable instance of [EvalGraderTextSimilarity]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): Python = - Python( + fun build(): EvalGraderTextSimilarity = + EvalGraderTextSimilarity( + checkRequired("evaluationMetric", evaluationMetric), + checkRequired("input", input), checkRequired("name", name), - checkRequired("source", source), + checkRequired("reference", reference), type, - imageTag, - passThreshold, + checkRequired("passThreshold", passThreshold), additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): Python = apply { + fun validate(): EvalGraderTextSimilarity = apply { if (validated) { return@apply } + evaluationMetric().validate() + input() name() - source() + reference() _type().let { - if (it != JsonValue.from("python")) { + if (it != JsonValue.from("text_similarity")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - imageTag() passThreshold() validated = true } @@ -1450,10 +1555,11 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (name.asKnown().isPresent) 1 else 0) + - (if (source.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("python")) 1 else 0 } + - (if (imageTag.asKnown().isPresent) 1 else 0) + + (evaluationMetric.asKnown().getOrNull()?.validity() ?: 0) + + (if (input.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (reference.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -1461,84 +1567,77 @@ private constructor( return true } - return /* spotless:off */ other is Python && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderTextSimilarity && evaluationMetric == other.evaluationMetric && input == other.input && name == other.name && reference == other.reference && type == other.type && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, name, reference, type, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Python{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + "EvalGraderTextSimilarity{evaluationMetric=$evaluationMetric, input=$input, name=$name, reference=$reference, type=$type, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } - /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - class ScoreModel + /** A PythonGrader object that runs a python script on the input. */ + class EvalGraderPython private constructor( - private val input: JsonField>, - private val model: JsonField, private val name: JsonField, + private val source: JsonField, private val type: JsonValue, + private val imageTag: JsonField, private val passThreshold: JsonField, - private val range: JsonField>, - private val samplingParams: JsonValue, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("input") - @ExcludeMissing - input: JsonField> = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("source") + @ExcludeMissing + source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("image_tag") + @ExcludeMissing + imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - @JsonProperty("range") - @ExcludeMissing - range: JsonField> = JsonMissing.of(), - @JsonProperty("sampling_params") - @ExcludeMissing - samplingParams: JsonValue = JsonMissing.of(), - ) : this(input, model, name, type, passThreshold, range, samplingParams, mutableMapOf()) + ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) - /** - * The input text. This may include template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun input(): List = input.getRequired("input") + fun toPythonGrader(): PythonGrader = + PythonGrader.builder() + .name(name) + .source(source) + .type(type) + .imageTag(imageTag) + .build() /** - * The model to use for the evaluation. + * The name of the grader. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun model(): String = model.getRequired("model") + fun name(): String = name.getRequired("name") /** - * The name of the grader. + * The source code of the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun name(): String = name.getRequired("name") + fun source(): String = source.getRequired("source") /** - * The object type, which is always `score_model`. + * The object type, which is always `python`. * * Expected to always return the following: * ```java - * JsonValue.from("score_model") + * JsonValue.from("python") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1547,46 +1646,42 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The threshold for the score. + * The image tag to use for the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + fun imageTag(): Optional = imageTag.getOptional("image_tag") /** - * The range of the score. Defaults to `[0, 1]`. + * The threshold for the score. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun range(): Optional> = range.getOptional("range") - - /** The sampling parameters for the model. */ - @JsonProperty("sampling_params") - @ExcludeMissing - fun _samplingParams(): JsonValue = samplingParams + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") /** - * Returns the raw JSON value of [input]. + * Returns the raw JSON value of [name]. * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("input") @ExcludeMissing fun _input(): JsonField> = input + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [model]. + * Returns the raw JSON value of [source]. * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [imageTag]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag /** * Returns the raw JSON value of [passThreshold]. @@ -1598,13 +1693,6 @@ private constructor( @ExcludeMissing fun _passThreshold(): JsonField = passThreshold - /** - * Returns the raw JSON value of [range]. - * - * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1620,80 +1708,37 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [ScoreModel]. + * Returns a mutable builder for constructing an instance of [EvalGraderPython]. * * The following fields are required: * ```java - * .input() - * .model() * .name() + * .source() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [ScoreModel]. */ + /** A builder for [EvalGraderPython]. */ class Builder internal constructor() { - private var input: JsonField>? = null - private var model: JsonField? = null private var name: JsonField? = null - private var type: JsonValue = JsonValue.from("score_model") + private var source: JsonField? = null + private var type: JsonValue = JsonValue.from("python") + private var imageTag: JsonField = JsonMissing.of() private var passThreshold: JsonField = JsonMissing.of() - private var range: JsonField>? = null - private var samplingParams: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(scoreModel: ScoreModel) = apply { - input = scoreModel.input.map { it.toMutableList() } - model = scoreModel.model - name = scoreModel.name - type = scoreModel.type - passThreshold = scoreModel.passThreshold - range = scoreModel.range.map { it.toMutableList() } - samplingParams = scoreModel.samplingParams - additionalProperties = scoreModel.additionalProperties.toMutableMap() - } - - /** The input text. This may include template strings. */ - fun input(input: List) = input(JsonField.of(input)) - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun input(input: JsonField>) = apply { - this.input = input.map { it.toMutableList() } - } - - /** - * Adds a single [Input] to [Builder.input]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addInput(input: Input) = apply { - this.input = - (this.input ?: JsonField.of(mutableListOf())).also { - checkKnown("input", it).add(input) - } + internal fun from(evalGraderPython: EvalGraderPython) = apply { + name = evalGraderPython.name + source = evalGraderPython.source + type = evalGraderPython.type + imageTag = evalGraderPython.imageTag + passThreshold = evalGraderPython.passThreshold + additionalProperties = evalGraderPython.additionalProperties.toMutableMap() } - /** The model to use for the evaluation. */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1706,8 +1751,410 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** The source code of the python script. */ + fun source(source: String) = source(JsonField.of(source)) + /** - * Sets the field to an arbitrary JSON value. + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("python") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The image tag to use for the python script. */ + fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) + + /** + * Sets [Builder.imageTag] to an arbitrary JSON value. + * + * You should usually call [Builder.imageTag] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } + + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [EvalGraderPython]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .source() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EvalGraderPython = + EvalGraderPython( + checkRequired("name", name), + checkRequired("source", source), + type, + imageTag, + passThreshold, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): EvalGraderPython = apply { + if (validated) { + return@apply + } + + name() + source() + _type().let { + if (it != JsonValue.from("python")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + imageTag() + passThreshold() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (if (source.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("python")) 1 else 0 } + + (if (imageTag.asKnown().isPresent) 1 else 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is EvalGraderPython && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "EvalGraderPython{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + } + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + class EvalGraderScoreModel + private constructor( + private val input: JsonField>, + private val model: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val range: JsonField>, + private val samplingParams: JsonValue, + private val passThreshold: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("input") + @ExcludeMissing + input: JsonField> = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("range") + @ExcludeMissing + range: JsonField> = JsonMissing.of(), + @JsonProperty("sampling_params") + @ExcludeMissing + samplingParams: JsonValue = JsonMissing.of(), + @JsonProperty("pass_threshold") + @ExcludeMissing + passThreshold: JsonField = JsonMissing.of(), + ) : this(input, model, name, type, range, samplingParams, passThreshold, mutableMapOf()) + + fun toScoreModelGrader(): ScoreModelGrader = + ScoreModelGrader.builder() + .input(input) + .model(model) + .name(name) + .type(type) + .range(range) + .samplingParams(samplingParams) + .build() + + /** + * The input text. This may include template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): List = input.getRequired("input") + + /** + * The model to use for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun model(): String = model.getRequired("model") + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") + + /** + * The object type, which is always `score_model`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The range of the score. Defaults to `[0, 1]`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun range(): Optional> = range.getOptional("range") + + /** The sampling parameters for the model. */ + @JsonProperty("sampling_params") + @ExcludeMissing + fun _samplingParams(): JsonValue = samplingParams + + /** + * The threshold for the score. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") + @ExcludeMissing + fun _input(): JsonField> = input + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [range]. + * + * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range + + /** + * Returns the raw JSON value of [passThreshold]. + * + * Unlike [passThreshold], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pass_threshold") + @ExcludeMissing + fun _passThreshold(): JsonField = passThreshold + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [EvalGraderScoreModel]. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [EvalGraderScoreModel]. */ + class Builder internal constructor() { + + private var input: JsonField>? = null + private var model: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("score_model") + private var range: JsonField>? = null + private var samplingParams: JsonValue = JsonMissing.of() + private var passThreshold: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(evalGraderScoreModel: EvalGraderScoreModel) = apply { + input = evalGraderScoreModel.input.map { it.toMutableList() } + model = evalGraderScoreModel.model + name = evalGraderScoreModel.name + type = evalGraderScoreModel.type + range = evalGraderScoreModel.range.map { it.toMutableList() } + samplingParams = evalGraderScoreModel.samplingParams + passThreshold = evalGraderScoreModel.passThreshold + additionalProperties = evalGraderScoreModel.additionalProperties.toMutableMap() + } + + /** The input text. This may include template strings. */ + fun input(input: List) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField>) = apply { + this.input = input.map { it.toMutableList() } + } + + /** + * Adds a single [ScoreModelGrader.Input] to [Builder.input]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addInput(input: ScoreModelGrader.Input) = apply { + this.input = + (this.input ?: JsonField.of(mutableListOf())).also { + checkKnown("input", it).add(input) + } + } + + /** The model to use for the evaluation. */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Sets the field to an arbitrary JSON value. * * It is usually unnecessary to call this method because the field defaults to the * following: @@ -1720,21 +2167,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The threshold for the score. */ - fun passThreshold(passThreshold: Double) = - passThreshold(JsonField.of(passThreshold)) - - /** - * Sets [Builder.passThreshold] to an arbitrary JSON value. - * - * You should usually call [Builder.passThreshold] with a well-typed [Double] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun passThreshold(passThreshold: JsonField) = apply { - this.passThreshold = passThreshold - } - /** The range of the score. Defaults to `[0, 1]`. */ fun range(range: List) = range(JsonField.of(range)) @@ -1766,6 +2198,21 @@ private constructor( this.samplingParams = samplingParams } + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1789,7 +2236,7 @@ private constructor( } /** - * Returns an immutable instance of [ScoreModel]. + * Returns an immutable instance of [EvalGraderScoreModel]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -1802,22 +2249,22 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): ScoreModel = - ScoreModel( + fun build(): EvalGraderScoreModel = + EvalGraderScoreModel( checkRequired("input", input).map { it.toImmutable() }, checkRequired("model", model), checkRequired("name", name), type, - passThreshold, (range ?: JsonMissing.of()).map { it.toImmutable() }, samplingParams, + passThreshold, additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): ScoreModel = apply { + fun validate(): EvalGraderScoreModel = apply { if (validated) { return@apply } @@ -1830,8 +2277,8 @@ private constructor( throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - passThreshold() range() + passThreshold() validated = true } @@ -1855,1003 +2302,25 @@ private constructor( (if (model.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + - (if (passThreshold.asKnown().isPresent) 1 else 0) + - (range.asKnown().getOrNull()?.size ?: 0) - - /** - * A message input to the model with a role indicating instruction following hierarchy. - * Instructions given with the `developer` or `system` role take precedence over - * instructions given with the `user` role. Messages with the `assistant` role are - * presumed to have been generated by the model in previous interactions. - */ - class Input - private constructor( - private val content: JsonField, - private val role: JsonField, - private val type: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("content") - @ExcludeMissing - content: JsonField = JsonMissing.of(), - @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(content, role, type, mutableMapOf()) - - /** - * Text inputs to the model - can contain template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun content(): Content = content.getRequired("content") - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun role(): Role = role.getRequired("role") - - /** - * The type of the message input. Always `message`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") - - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("content") - @ExcludeMissing - fun _content(): JsonField = content - - /** - * Returns the raw JSON value of [role]. - * - * Unlike [role], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Input]. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Input]. */ - class Builder internal constructor() { - - private var content: JsonField? = null - private var role: JsonField? = null - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(input: Input) = apply { - content = input.content - role = input.role - type = input.type - additionalProperties = input.additionalProperties.toMutableMap() - } - - /** Text inputs to the model - can contain template strings. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - - /** Alias for calling [content] with `Content.ofTextInput(textInput)`. */ - fun content(textInput: String) = content(Content.ofTextInput(textInput)) - - /** - * Alias for calling [content] with - * `Content.ofResponseInputText(responseInputText)`. - */ - fun content(responseInputText: ResponseInputText) = - content(Content.ofResponseInputText(responseInputText)) - - /** Alias for calling [content] with `Content.ofOutputText(outputText)`. */ - fun content(outputText: Content.OutputText) = - content(Content.ofOutputText(outputText)) - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - fun role(role: Role) = role(JsonField.of(role)) - - /** - * Sets [Builder.role] to an arbitrary JSON value. - * - * You should usually call [Builder.role] with a well-typed [Role] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun role(role: JsonField) = apply { this.role = role } - - /** The type of the message input. Always `message`. */ - fun type(type: Type) = type(JsonField.of(type)) - - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Input]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Input = - Input( - checkRequired("content", content), - checkRequired("role", role), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Input = apply { - if (validated) { - return@apply - } - - content().validate() - role().validate() - type().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (content.asKnown().getOrNull()?.validity() ?: 0) + - (role.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) - - /** Text inputs to the model - can contain template strings. */ - @JsonDeserialize(using = Content.Deserializer::class) - @JsonSerialize(using = Content.Serializer::class) - class Content - private constructor( - private val textInput: String? = null, - private val responseInputText: ResponseInputText? = null, - private val outputText: OutputText? = null, - private val _json: JsonValue? = null, - ) { - - /** A text input to the model. */ - fun textInput(): Optional = Optional.ofNullable(textInput) - - /** A text input to the model. */ - fun responseInputText(): Optional = - Optional.ofNullable(responseInputText) - - /** A text output from the model. */ - fun outputText(): Optional = Optional.ofNullable(outputText) - - fun isTextInput(): Boolean = textInput != null - - fun isResponseInputText(): Boolean = responseInputText != null - - fun isOutputText(): Boolean = outputText != null - - /** A text input to the model. */ - fun asTextInput(): String = textInput.getOrThrow("textInput") - - /** A text input to the model. */ - fun asResponseInputText(): ResponseInputText = - responseInputText.getOrThrow("responseInputText") - - /** A text output from the model. */ - fun asOutputText(): OutputText = outputText.getOrThrow("outputText") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - textInput != null -> visitor.visitTextInput(textInput) - responseInputText != null -> - visitor.visitResponseInputText(responseInputText) - outputText != null -> visitor.visitOutputText(outputText) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Content = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitTextInput(textInput: String) {} - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) { - responseInputText.validate() - } - - override fun visitOutputText(outputText: OutputText) { - outputText.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitTextInput(textInput: String) = 1 - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) = responseInputText.validity() - - override fun visitOutputText(outputText: OutputText) = - outputText.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && textInput == other.textInput && responseInputText == other.responseInputText && outputText == other.outputText /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(textInput, responseInputText, outputText) /* spotless:on */ - - override fun toString(): String = - when { - textInput != null -> "Content{textInput=$textInput}" - responseInputText != null -> - "Content{responseInputText=$responseInputText}" - outputText != null -> "Content{outputText=$outputText}" - _json != null -> "Content{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Content") - } - - companion object { - - /** A text input to the model. */ - @JvmStatic - fun ofTextInput(textInput: String) = Content(textInput = textInput) - - /** A text input to the model. */ - @JvmStatic - fun ofResponseInputText(responseInputText: ResponseInputText) = - Content(responseInputText = responseInputText) - - /** A text output from the model. */ - @JvmStatic - fun ofOutputText(outputText: OutputText) = Content(outputText = outputText) - } - - /** - * An interface that defines how to map each variant of [Content] to a value of - * type [T]. - */ - interface Visitor { - - /** A text input to the model. */ - fun visitTextInput(textInput: String): T - - /** A text input to the model. */ - fun visitResponseInputText(responseInputText: ResponseInputText): T - - /** A text output from the model. */ - fun visitOutputText(outputText: OutputText): T - - /** - * Maps an unknown variant of [Content] to a value of type [T]. - * - * An instance of [Content] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Content: $json") - } - } - - internal class Deserializer : BaseDeserializer(Content::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Content { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Content(responseInputText = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(outputText = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(textInput = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from array). - 0 -> Content(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Content::class) { - - override fun serialize( - value: Content, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.textInput != null -> generator.writeObject(value.textInput) - value.responseInputText != null -> - generator.writeObject(value.responseInputText) - value.outputText != null -> generator.writeObject(value.outputText) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Content") - } - } - } - - /** A text output from the model. */ - class OutputText - private constructor( - private val text: JsonField, - private val type: JsonValue, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("text") - @ExcludeMissing - text: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - ) : this(text, type, mutableMapOf()) - - /** - * The text output from the model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded - * with an unexpected value). - */ - fun text(): String = text.getRequired("text") - - /** - * The type of the output text. Always `output_text`. - * - * Expected to always return the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * However, this method can be useful for debugging and logging (e.g. if the - * server responded with an unexpected value). - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - - /** - * Returns the raw JSON value of [text]. - * - * Unlike [text], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [OutputText]. - * - * The following fields are required: - * ```java - * .text() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [OutputText]. */ - class Builder internal constructor() { - - private var text: JsonField? = null - private var type: JsonValue = JsonValue.from("output_text") - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(outputText: OutputText) = apply { - text = outputText.text - type = outputText.type - additionalProperties = - outputText.additionalProperties.toMutableMap() - } - - /** The text output from the model. */ - fun text(text: String) = text(JsonField.of(text)) - - /** - * Sets [Builder.text] to an arbitrary JSON value. - * - * You should usually call [Builder.text] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun text(text: JsonField) = apply { this.text = text } - - /** - * Sets the field to an arbitrary JSON value. - * - * It is usually unnecessary to call this method because the field - * defaults to the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonValue) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [OutputText]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - * - * The following fields are required: - * ```java - * .text() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): OutputText = - OutputText( - checkRequired("text", text), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): OutputText = apply { - if (validated) { - return@apply - } - - text() - _type().let { - if (it != JsonValue.from("output_text")) { - throw OpenAIInvalidDataException( - "'type' is invalid, received $it" - ) - } - } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (text.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("output_text")) 1 else 0 } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is OutputText && text == other.text && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(text, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "OutputText{text=$text, type=$type, additionalProperties=$additionalProperties}" - } - } - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - class Role @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val USER = of("user") - - @JvmField val ASSISTANT = of("assistant") - - @JvmField val SYSTEM = of("system") - - @JvmField val DEVELOPER = of("developer") - - @JvmStatic fun of(value: String) = Role(JsonField.of(value)) - } - - /** An enum containing [Role]'s known values. */ - enum class Known { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - } - - /** - * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Role] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - /** - * An enum member indicating that [Role] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - USER -> Value.USER - ASSISTANT -> Value.ASSISTANT - SYSTEM -> Value.SYSTEM - DEVELOPER -> Value.DEVELOPER - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - USER -> Known.USER - ASSISTANT -> Known.ASSISTANT - SYSTEM -> Known.SYSTEM - DEVELOPER -> Known.DEVELOPER - else -> throw OpenAIInvalidDataException("Unknown Role: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Role = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Role && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - /** The type of the message input. Always `message`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val MESSAGE = of("message") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - MESSAGE - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - MESSAGE, - /** - * An enum member indicating that [Type] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - MESSAGE -> Value.MESSAGE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - MESSAGE -> Known.MESSAGE - else -> throw OpenAIInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Type && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Input && content == other.content && role == other.role && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(content, role, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Input{content=$content, role=$role, type=$type, additionalProperties=$additionalProperties}" - } + (range.asKnown().getOrNull()?.size ?: 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && passThreshold == other.passThreshold && range == other.range && samplingParams == other.samplingParams && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && range == other.range && samplingParams == other.samplingParams && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(input, model, name, type, passThreshold, range, samplingParams, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(input, model, name, type, range, samplingParams, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "ScoreModel{input=$input, model=$model, name=$name, type=$type, passThreshold=$passThreshold, range=$range, samplingParams=$samplingParams, additionalProperties=$additionalProperties}" + "EvalGraderScoreModel{input=$input, model=$model, name=$name, type=$type, range=$range, samplingParams=$samplingParams, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveParams.kt index 63111243d..3a411a0bc 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveParams.kt @@ -3,20 +3,21 @@ package com.openai.models.evals import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Get an evaluation by ID. */ class EvalRetrieveParams private constructor( - private val evalId: String, + private val evalId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun evalId(): String = evalId + fun evalId(): Optional = Optional.ofNullable(evalId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,14 +27,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [EvalRetrieveParams]. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - */ + @JvmStatic fun none(): EvalRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [EvalRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -51,7 +47,10 @@ private constructor( additionalQueryParams = evalRetrieveParams.additionalQueryParams.toBuilder() } - fun evalId(evalId: String) = apply { this.evalId = evalId } + fun evalId(evalId: String?) = apply { this.evalId = evalId } + + /** Alias for calling [Builder.evalId] with `evalId.orElse(null)`. */ + fun evalId(evalId: Optional) = evalId(evalId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,25 +154,14 @@ private constructor( * Returns an immutable instance of [EvalRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): EvalRetrieveParams = - EvalRetrieveParams( - checkRequired("evalId", evalId), - additionalHeaders.build(), - additionalQueryParams.build(), - ) + EvalRetrieveParams(evalId, additionalHeaders.build(), additionalQueryParams.build()) } fun _pathParam(index: Int): String = when (index) { - 0 -> evalId + 0 -> evalId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveResponse.kt index f420c699d..56c27978d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveResponse.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalRetrieveResponse.kt @@ -15,7 +15,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.BaseDeserializer import com.openai.core.BaseSerializer -import com.openai.core.Enum import com.openai.core.ExcludeMissing import com.openai.core.JsonField import com.openai.core.JsonMissing @@ -26,7 +25,11 @@ import com.openai.core.checkRequired import com.openai.core.getOrThrow import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException -import com.openai.models.responses.ResponseInputText +import com.openai.models.graders.gradermodels.LabelModelGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader import java.util.Collections import java.util.Objects import java.util.Optional @@ -388,34 +391,43 @@ private constructor( } /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofLabelModel(labelModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofLabelModelGrader(labelModelGrader)`. */ - fun addTestingCriterion(labelModel: EvalLabelModelGrader) = - addTestingCriterion(TestingCriterion.ofLabelModel(labelModel)) + fun addTestingCriterion(labelModelGrader: LabelModelGrader) = + addTestingCriterion(TestingCriterion.ofLabelModelGrader(labelModelGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofStringCheck(stringCheck)`. + * `TestingCriterion.ofStringCheckGrader(stringCheckGrader)`. */ - fun addTestingCriterion(stringCheck: EvalStringCheckGrader) = - addTestingCriterion(TestingCriterion.ofStringCheck(stringCheck)) + fun addTestingCriterion(stringCheckGrader: StringCheckGrader) = + addTestingCriterion(TestingCriterion.ofStringCheckGrader(stringCheckGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofTextSimilarity(textSimilarity)`. + * `TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity)`. */ - fun addTestingCriterion(textSimilarity: EvalTextSimilarityGrader) = - addTestingCriterion(TestingCriterion.ofTextSimilarity(textSimilarity)) + fun addTestingCriterion( + evalGraderTextSimilarity: TestingCriterion.EvalGraderTextSimilarity + ) = + addTestingCriterion( + TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity) + ) - /** Alias for calling [addTestingCriterion] with `TestingCriterion.ofPython(python)`. */ - fun addTestingCriterion(python: TestingCriterion.Python) = - addTestingCriterion(TestingCriterion.ofPython(python)) + /** + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderPython(evalGraderPython)`. + */ + fun addTestingCriterion(evalGraderPython: TestingCriterion.EvalGraderPython) = + addTestingCriterion(TestingCriterion.ofEvalGraderPython(evalGraderPython)) /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofScoreModel(scoreModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)`. */ - fun addTestingCriterion(scoreModel: TestingCriterion.ScoreModel) = - addTestingCriterion(TestingCriterion.ofScoreModel(scoreModel)) + fun addTestingCriterion(evalGraderScoreModel: TestingCriterion.EvalGraderScoreModel) = + addTestingCriterion(TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)) fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -860,11 +872,11 @@ private constructor( @JsonSerialize(using = TestingCriterion.Serializer::class) class TestingCriterion private constructor( - private val labelModel: EvalLabelModelGrader? = null, - private val stringCheck: EvalStringCheckGrader? = null, - private val textSimilarity: EvalTextSimilarityGrader? = null, - private val python: Python? = null, - private val scoreModel: ScoreModel? = null, + private val labelModelGrader: LabelModelGrader? = null, + private val stringCheckGrader: StringCheckGrader? = null, + private val evalGraderTextSimilarity: EvalGraderTextSimilarity? = null, + private val evalGraderPython: EvalGraderPython? = null, + private val evalGraderScoreModel: EvalGraderScoreModel? = null, private val _json: JsonValue? = null, ) { @@ -872,65 +884,71 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun labelModel(): Optional = Optional.ofNullable(labelModel) + fun labelModelGrader(): Optional = Optional.ofNullable(labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + fun stringCheckGrader(): Optional = + Optional.ofNullable(stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun textSimilarity(): Optional = - Optional.ofNullable(textSimilarity) + fun evalGraderTextSimilarity(): Optional = + Optional.ofNullable(evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - fun python(): Optional = Optional.ofNullable(python) + fun evalGraderPython(): Optional = Optional.ofNullable(evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + fun evalGraderScoreModel(): Optional = + Optional.ofNullable(evalGraderScoreModel) - fun isLabelModel(): Boolean = labelModel != null + fun isLabelModelGrader(): Boolean = labelModelGrader != null - fun isStringCheck(): Boolean = stringCheck != null + fun isStringCheckGrader(): Boolean = stringCheckGrader != null - fun isTextSimilarity(): Boolean = textSimilarity != null + fun isEvalGraderTextSimilarity(): Boolean = evalGraderTextSimilarity != null - fun isPython(): Boolean = python != null + fun isEvalGraderPython(): Boolean = evalGraderPython != null - fun isScoreModel(): Boolean = scoreModel != null + fun isEvalGraderScoreModel(): Boolean = evalGraderScoreModel != null /** * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun asLabelModel(): EvalLabelModelGrader = labelModel.getOrThrow("labelModel") + fun asLabelModelGrader(): LabelModelGrader = labelModelGrader.getOrThrow("labelModelGrader") /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun asStringCheck(): EvalStringCheckGrader = stringCheck.getOrThrow("stringCheck") + fun asStringCheckGrader(): StringCheckGrader = + stringCheckGrader.getOrThrow("stringCheckGrader") /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun asTextSimilarity(): EvalTextSimilarityGrader = - textSimilarity.getOrThrow("textSimilarity") + fun asEvalGraderTextSimilarity(): EvalGraderTextSimilarity = + evalGraderTextSimilarity.getOrThrow("evalGraderTextSimilarity") /** A PythonGrader object that runs a python script on the input. */ - fun asPython(): Python = python.getOrThrow("python") + fun asEvalGraderPython(): EvalGraderPython = evalGraderPython.getOrThrow("evalGraderPython") /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun asScoreModel(): ScoreModel = scoreModel.getOrThrow("scoreModel") + fun asEvalGraderScoreModel(): EvalGraderScoreModel = + evalGraderScoreModel.getOrThrow("evalGraderScoreModel") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { - labelModel != null -> visitor.visitLabelModel(labelModel) - stringCheck != null -> visitor.visitStringCheck(stringCheck) - textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) - python != null -> visitor.visitPython(python) - scoreModel != null -> visitor.visitScoreModel(scoreModel) + labelModelGrader != null -> visitor.visitLabelModelGrader(labelModelGrader) + stringCheckGrader != null -> visitor.visitStringCheckGrader(stringCheckGrader) + evalGraderTextSimilarity != null -> + visitor.visitEvalGraderTextSimilarity(evalGraderTextSimilarity) + evalGraderPython != null -> visitor.visitEvalGraderPython(evalGraderPython) + evalGraderScoreModel != null -> + visitor.visitEvalGraderScoreModel(evalGraderScoreModel) else -> visitor.unknown(_json) } @@ -943,24 +961,28 @@ private constructor( accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) { - labelModel.validate() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) { + labelModelGrader.validate() } - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) { - stringCheck.validate() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) { + stringCheckGrader.validate() } - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) { - textSimilarity.validate() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) { + evalGraderTextSimilarity.validate() } - override fun visitPython(python: Python) { - python.validate() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) { + evalGraderPython.validate() } - override fun visitScoreModel(scoreModel: ScoreModel) { - scoreModel.validate() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) { + evalGraderScoreModel.validate() } } ) @@ -985,18 +1007,22 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) = - labelModel.validity() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) = + labelModelGrader.validity() - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) = - stringCheck.validity() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) = + stringCheckGrader.validity() - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - textSimilarity.validity() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) = evalGraderTextSimilarity.validity() - override fun visitPython(python: Python) = python.validity() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) = + evalGraderPython.validity() - override fun visitScoreModel(scoreModel: ScoreModel) = scoreModel.validity() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) = evalGraderScoreModel.validity() override fun unknown(json: JsonValue?) = 0 } @@ -1007,18 +1033,21 @@ private constructor( return true } - return /* spotless:off */ other is TestingCriterion && labelModel == other.labelModel && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel /* spotless:on */ + return /* spotless:off */ other is TestingCriterion && labelModelGrader == other.labelModelGrader && stringCheckGrader == other.stringCheckGrader && evalGraderTextSimilarity == other.evalGraderTextSimilarity && evalGraderPython == other.evalGraderPython && evalGraderScoreModel == other.evalGraderScoreModel /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModel, stringCheck, textSimilarity, python, scoreModel) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModelGrader, stringCheckGrader, evalGraderTextSimilarity, evalGraderPython, evalGraderScoreModel) /* spotless:on */ override fun toString(): String = when { - labelModel != null -> "TestingCriterion{labelModel=$labelModel}" - stringCheck != null -> "TestingCriterion{stringCheck=$stringCheck}" - textSimilarity != null -> "TestingCriterion{textSimilarity=$textSimilarity}" - python != null -> "TestingCriterion{python=$python}" - scoreModel != null -> "TestingCriterion{scoreModel=$scoreModel}" + labelModelGrader != null -> "TestingCriterion{labelModelGrader=$labelModelGrader}" + stringCheckGrader != null -> + "TestingCriterion{stringCheckGrader=$stringCheckGrader}" + evalGraderTextSimilarity != null -> + "TestingCriterion{evalGraderTextSimilarity=$evalGraderTextSimilarity}" + evalGraderPython != null -> "TestingCriterion{evalGraderPython=$evalGraderPython}" + evalGraderScoreModel != null -> + "TestingCriterion{evalGraderScoreModel=$evalGraderScoreModel}" _json != null -> "TestingCriterion{_unknown=$_json}" else -> throw IllegalStateException("Invalid TestingCriterion") } @@ -1030,28 +1059,31 @@ private constructor( * evaluation. */ @JvmStatic - fun ofLabelModel(labelModel: EvalLabelModelGrader) = - TestingCriterion(labelModel = labelModel) + fun ofLabelModelGrader(labelModelGrader: LabelModelGrader) = + TestingCriterion(labelModelGrader = labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ @JvmStatic - fun ofStringCheck(stringCheck: EvalStringCheckGrader) = - TestingCriterion(stringCheck = stringCheck) + fun ofStringCheckGrader(stringCheckGrader: StringCheckGrader) = + TestingCriterion(stringCheckGrader = stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ @JvmStatic - fun ofTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - TestingCriterion(textSimilarity = textSimilarity) + fun ofEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity) = + TestingCriterion(evalGraderTextSimilarity = evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - @JvmStatic fun ofPython(python: Python) = TestingCriterion(python = python) + @JvmStatic + fun ofEvalGraderPython(evalGraderPython: EvalGraderPython) = + TestingCriterion(evalGraderPython = evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ @JvmStatic - fun ofScoreModel(scoreModel: ScoreModel) = TestingCriterion(scoreModel = scoreModel) + fun ofEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel) = + TestingCriterion(evalGraderScoreModel = evalGraderScoreModel) } /** @@ -1064,22 +1096,22 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun visitLabelModel(labelModel: EvalLabelModelGrader): T + fun visitLabelModelGrader(labelModelGrader: LabelModelGrader): T /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ - fun visitStringCheck(stringCheck: EvalStringCheckGrader): T + fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader): T /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader): T + fun visitEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity): T /** A PythonGrader object that runs a python script on the input. */ - fun visitPython(python: Python): T + fun visitEvalGraderPython(evalGraderPython: EvalGraderPython): T /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun visitScoreModel(scoreModel: ScoreModel): T + fun visitEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel): T /** * Maps an unknown variant of [TestingCriterion] to a value of type [T]. @@ -1100,37 +1132,38 @@ private constructor( override fun ObjectCodec.deserialize(node: JsonNode): TestingCriterion { val json = JsonValue.fromJsonNode(node) - val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() - when (type) { - "label_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(labelModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "string_check" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(stringCheck = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "text_similarity" -> { - return tryDeserialize(node, jacksonTypeRef()) - ?.let { TestingCriterion(textSimilarity = it, _json = json) } - ?: TestingCriterion(_json = json) - } - "python" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(python = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "score_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(scoreModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(labelModelGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(stringCheckGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderTextSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderPython = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderScoreModel = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> TestingCriterion(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() } - - return TestingCriterion(_json = json) } } @@ -1142,42 +1175,77 @@ private constructor( provider: SerializerProvider, ) { when { - value.labelModel != null -> generator.writeObject(value.labelModel) - value.stringCheck != null -> generator.writeObject(value.stringCheck) - value.textSimilarity != null -> generator.writeObject(value.textSimilarity) - value.python != null -> generator.writeObject(value.python) - value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.labelModelGrader != null -> generator.writeObject(value.labelModelGrader) + value.stringCheckGrader != null -> + generator.writeObject(value.stringCheckGrader) + value.evalGraderTextSimilarity != null -> + generator.writeObject(value.evalGraderTextSimilarity) + value.evalGraderPython != null -> generator.writeObject(value.evalGraderPython) + value.evalGraderScoreModel != null -> + generator.writeObject(value.evalGraderScoreModel) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid TestingCriterion") } } } - /** A PythonGrader object that runs a python script on the input. */ - class Python + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + class EvalGraderTextSimilarity private constructor( + private val evaluationMetric: JsonField, + private val input: JsonField, private val name: JsonField, - private val source: JsonField, + private val reference: JsonField, private val type: JsonValue, - private val imageTag: JsonField, private val passThreshold: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( + @JsonProperty("evaluation_metric") + @ExcludeMissing + evaluationMetric: JsonField = + JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("source") + @JsonProperty("reference") @ExcludeMissing - source: JsonField = JsonMissing.of(), + reference: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - @JsonProperty("image_tag") - @ExcludeMissing - imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) + ) : this(evaluationMetric, input, name, reference, type, passThreshold, mutableMapOf()) + + fun toTextSimilarityGrader(): TextSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(evaluationMetric) + .input(input) + .name(name) + .reference(reference) + .type(type) + .build() + + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun evaluationMetric(): TextSimilarityGrader.EvaluationMetric = + evaluationMetric.getRequired("evaluation_metric") + + /** + * The text being graded. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): String = input.getRequired("input") /** * The name of the grader. @@ -1189,20 +1257,20 @@ private constructor( fun name(): String = name.getRequired("name") /** - * The source code of the python script. + * The text being graded against. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun source(): String = source.getRequired("source") + fun reference(): String = reference.getRequired("reference") /** - * The object type, which is always `python`. + * The type of grader. * * Expected to always return the following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1211,42 +1279,48 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The image tag to use for the python script. + * The threshold for the score. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun imageTag(): Optional = imageTag.getOptional("image_tag") + fun passThreshold(): Double = passThreshold.getRequired("pass_threshold") /** - * The threshold for the score. + * Returns the raw JSON value of [evaluationMetric]. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * Unlike [evaluationMetric], this method doesn't throw if the JSON field has an + * unexpected type. */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + @JsonProperty("evaluation_metric") + @ExcludeMissing + fun _evaluationMetric(): JsonField = + evaluationMetric /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [input]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input /** - * Returns the raw JSON value of [source]. + * Returns the raw JSON value of [name]. * - * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [imageTag]. + * Returns the raw JSON value of [reference]. * - * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * Unlike [reference], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag + @JsonProperty("reference") + @ExcludeMissing + fun _reference(): JsonField = reference /** * Returns the raw JSON value of [passThreshold]. @@ -1273,37 +1347,75 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [Python]. + * Returns a mutable builder for constructing an instance of + * [EvalGraderTextSimilarity]. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [Python]. */ + /** A builder for [EvalGraderTextSimilarity]. */ class Builder internal constructor() { + private var evaluationMetric: JsonField? = + null + private var input: JsonField? = null private var name: JsonField? = null - private var source: JsonField? = null - private var type: JsonValue = JsonValue.from("python") - private var imageTag: JsonField = JsonMissing.of() - private var passThreshold: JsonField = JsonMissing.of() + private var reference: JsonField? = null + private var type: JsonValue = JsonValue.from("text_similarity") + private var passThreshold: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(python: Python) = apply { - name = python.name - source = python.source - type = python.type - imageTag = python.imageTag - passThreshold = python.passThreshold - additionalProperties = python.additionalProperties.toMutableMap() + internal fun from(evalGraderTextSimilarity: EvalGraderTextSimilarity) = apply { + evaluationMetric = evalGraderTextSimilarity.evaluationMetric + input = evalGraderTextSimilarity.input + name = evalGraderTextSimilarity.name + reference = evalGraderTextSimilarity.reference + type = evalGraderTextSimilarity.type + passThreshold = evalGraderTextSimilarity.passThreshold + additionalProperties = + evalGraderTextSimilarity.additionalProperties.toMutableMap() } + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + */ + fun evaluationMetric(evaluationMetric: TextSimilarityGrader.EvaluationMetric) = + evaluationMetric(JsonField.of(evaluationMetric)) + + /** + * Sets [Builder.evaluationMetric] to an arbitrary JSON value. + * + * You should usually call [Builder.evaluationMetric] with a well-typed + * [TextSimilarityGrader.EvaluationMetric] value instead. This method is primarily + * for setting the field to an undocumented or not yet supported value. + */ + fun evaluationMetric( + evaluationMetric: JsonField + ) = apply { this.evaluationMetric = evaluationMetric } + + /** The text being graded. */ + fun input(input: String) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun input(input: JsonField) = apply { this.input = input } + /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1316,17 +1428,17 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } - /** The source code of the python script. */ - fun source(source: String) = source(JsonField.of(source)) + /** The text being graded against. */ + fun reference(reference: String) = reference(JsonField.of(reference)) /** - * Sets [Builder.source] to an arbitrary JSON value. + * Sets [Builder.reference] to an arbitrary JSON value. * - * You should usually call [Builder.source] with a well-typed [String] value + * You should usually call [Builder.reference] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun source(source: JsonField) = apply { this.source = source } + fun reference(reference: JsonField) = apply { this.reference = reference } /** * Sets the field to an arbitrary JSON value. @@ -1334,7 +1446,7 @@ private constructor( * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -1342,18 +1454,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The image tag to use for the python script. */ - fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) - - /** - * Sets [Builder.imageTag] to an arbitrary JSON value. - * - * You should usually call [Builder.imageTag] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } - /** The threshold for the score. */ fun passThreshold(passThreshold: Double) = passThreshold(JsonField.of(passThreshold)) @@ -1392,44 +1492,49 @@ private constructor( } /** - * Returns an immutable instance of [Python]. + * Returns an immutable instance of [EvalGraderTextSimilarity]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): Python = - Python( + fun build(): EvalGraderTextSimilarity = + EvalGraderTextSimilarity( + checkRequired("evaluationMetric", evaluationMetric), + checkRequired("input", input), checkRequired("name", name), - checkRequired("source", source), + checkRequired("reference", reference), type, - imageTag, - passThreshold, + checkRequired("passThreshold", passThreshold), additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): Python = apply { + fun validate(): EvalGraderTextSimilarity = apply { if (validated) { return@apply } + evaluationMetric().validate() + input() name() - source() + reference() _type().let { - if (it != JsonValue.from("python")) { + if (it != JsonValue.from("text_similarity")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - imageTag() passThreshold() validated = true } @@ -1450,10 +1555,11 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (name.asKnown().isPresent) 1 else 0) + - (if (source.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("python")) 1 else 0 } + - (if (imageTag.asKnown().isPresent) 1 else 0) + + (evaluationMetric.asKnown().getOrNull()?.validity() ?: 0) + + (if (input.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (reference.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -1461,84 +1567,77 @@ private constructor( return true } - return /* spotless:off */ other is Python && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderTextSimilarity && evaluationMetric == other.evaluationMetric && input == other.input && name == other.name && reference == other.reference && type == other.type && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, name, reference, type, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Python{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + "EvalGraderTextSimilarity{evaluationMetric=$evaluationMetric, input=$input, name=$name, reference=$reference, type=$type, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } - /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - class ScoreModel + /** A PythonGrader object that runs a python script on the input. */ + class EvalGraderPython private constructor( - private val input: JsonField>, - private val model: JsonField, private val name: JsonField, + private val source: JsonField, private val type: JsonValue, + private val imageTag: JsonField, private val passThreshold: JsonField, - private val range: JsonField>, - private val samplingParams: JsonValue, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("input") - @ExcludeMissing - input: JsonField> = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("source") + @ExcludeMissing + source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("image_tag") + @ExcludeMissing + imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - @JsonProperty("range") - @ExcludeMissing - range: JsonField> = JsonMissing.of(), - @JsonProperty("sampling_params") - @ExcludeMissing - samplingParams: JsonValue = JsonMissing.of(), - ) : this(input, model, name, type, passThreshold, range, samplingParams, mutableMapOf()) + ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) - /** - * The input text. This may include template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun input(): List = input.getRequired("input") + fun toPythonGrader(): PythonGrader = + PythonGrader.builder() + .name(name) + .source(source) + .type(type) + .imageTag(imageTag) + .build() /** - * The model to use for the evaluation. + * The name of the grader. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun model(): String = model.getRequired("model") + fun name(): String = name.getRequired("name") /** - * The name of the grader. + * The source code of the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun name(): String = name.getRequired("name") + fun source(): String = source.getRequired("source") /** - * The object type, which is always `score_model`. + * The object type, which is always `python`. * * Expected to always return the following: * ```java - * JsonValue.from("score_model") + * JsonValue.from("python") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1547,46 +1646,42 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The threshold for the score. + * The image tag to use for the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + fun imageTag(): Optional = imageTag.getOptional("image_tag") /** - * The range of the score. Defaults to `[0, 1]`. + * The threshold for the score. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun range(): Optional> = range.getOptional("range") - - /** The sampling parameters for the model. */ - @JsonProperty("sampling_params") - @ExcludeMissing - fun _samplingParams(): JsonValue = samplingParams + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") /** - * Returns the raw JSON value of [input]. + * Returns the raw JSON value of [name]. * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("input") @ExcludeMissing fun _input(): JsonField> = input + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [model]. + * Returns the raw JSON value of [source]. * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [imageTag]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag /** * Returns the raw JSON value of [passThreshold]. @@ -1598,13 +1693,6 @@ private constructor( @ExcludeMissing fun _passThreshold(): JsonField = passThreshold - /** - * Returns the raw JSON value of [range]. - * - * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1620,80 +1708,37 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [ScoreModel]. + * Returns a mutable builder for constructing an instance of [EvalGraderPython]. * * The following fields are required: * ```java - * .input() - * .model() * .name() + * .source() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [ScoreModel]. */ + /** A builder for [EvalGraderPython]. */ class Builder internal constructor() { - private var input: JsonField>? = null - private var model: JsonField? = null private var name: JsonField? = null - private var type: JsonValue = JsonValue.from("score_model") + private var source: JsonField? = null + private var type: JsonValue = JsonValue.from("python") + private var imageTag: JsonField = JsonMissing.of() private var passThreshold: JsonField = JsonMissing.of() - private var range: JsonField>? = null - private var samplingParams: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(scoreModel: ScoreModel) = apply { - input = scoreModel.input.map { it.toMutableList() } - model = scoreModel.model - name = scoreModel.name - type = scoreModel.type - passThreshold = scoreModel.passThreshold - range = scoreModel.range.map { it.toMutableList() } - samplingParams = scoreModel.samplingParams - additionalProperties = scoreModel.additionalProperties.toMutableMap() - } - - /** The input text. This may include template strings. */ - fun input(input: List) = input(JsonField.of(input)) - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun input(input: JsonField>) = apply { - this.input = input.map { it.toMutableList() } - } - - /** - * Adds a single [Input] to [Builder.input]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addInput(input: Input) = apply { - this.input = - (this.input ?: JsonField.of(mutableListOf())).also { - checkKnown("input", it).add(input) - } + internal fun from(evalGraderPython: EvalGraderPython) = apply { + name = evalGraderPython.name + source = evalGraderPython.source + type = evalGraderPython.type + imageTag = evalGraderPython.imageTag + passThreshold = evalGraderPython.passThreshold + additionalProperties = evalGraderPython.additionalProperties.toMutableMap() } - /** The model to use for the evaluation. */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1706,8 +1751,410 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** The source code of the python script. */ + fun source(source: String) = source(JsonField.of(source)) + /** - * Sets the field to an arbitrary JSON value. + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("python") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The image tag to use for the python script. */ + fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) + + /** + * Sets [Builder.imageTag] to an arbitrary JSON value. + * + * You should usually call [Builder.imageTag] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } + + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [EvalGraderPython]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .source() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EvalGraderPython = + EvalGraderPython( + checkRequired("name", name), + checkRequired("source", source), + type, + imageTag, + passThreshold, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): EvalGraderPython = apply { + if (validated) { + return@apply + } + + name() + source() + _type().let { + if (it != JsonValue.from("python")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + imageTag() + passThreshold() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (if (source.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("python")) 1 else 0 } + + (if (imageTag.asKnown().isPresent) 1 else 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is EvalGraderPython && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "EvalGraderPython{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + } + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + class EvalGraderScoreModel + private constructor( + private val input: JsonField>, + private val model: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val range: JsonField>, + private val samplingParams: JsonValue, + private val passThreshold: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("input") + @ExcludeMissing + input: JsonField> = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("range") + @ExcludeMissing + range: JsonField> = JsonMissing.of(), + @JsonProperty("sampling_params") + @ExcludeMissing + samplingParams: JsonValue = JsonMissing.of(), + @JsonProperty("pass_threshold") + @ExcludeMissing + passThreshold: JsonField = JsonMissing.of(), + ) : this(input, model, name, type, range, samplingParams, passThreshold, mutableMapOf()) + + fun toScoreModelGrader(): ScoreModelGrader = + ScoreModelGrader.builder() + .input(input) + .model(model) + .name(name) + .type(type) + .range(range) + .samplingParams(samplingParams) + .build() + + /** + * The input text. This may include template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): List = input.getRequired("input") + + /** + * The model to use for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun model(): String = model.getRequired("model") + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") + + /** + * The object type, which is always `score_model`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The range of the score. Defaults to `[0, 1]`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun range(): Optional> = range.getOptional("range") + + /** The sampling parameters for the model. */ + @JsonProperty("sampling_params") + @ExcludeMissing + fun _samplingParams(): JsonValue = samplingParams + + /** + * The threshold for the score. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") + @ExcludeMissing + fun _input(): JsonField> = input + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [range]. + * + * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range + + /** + * Returns the raw JSON value of [passThreshold]. + * + * Unlike [passThreshold], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pass_threshold") + @ExcludeMissing + fun _passThreshold(): JsonField = passThreshold + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [EvalGraderScoreModel]. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [EvalGraderScoreModel]. */ + class Builder internal constructor() { + + private var input: JsonField>? = null + private var model: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("score_model") + private var range: JsonField>? = null + private var samplingParams: JsonValue = JsonMissing.of() + private var passThreshold: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(evalGraderScoreModel: EvalGraderScoreModel) = apply { + input = evalGraderScoreModel.input.map { it.toMutableList() } + model = evalGraderScoreModel.model + name = evalGraderScoreModel.name + type = evalGraderScoreModel.type + range = evalGraderScoreModel.range.map { it.toMutableList() } + samplingParams = evalGraderScoreModel.samplingParams + passThreshold = evalGraderScoreModel.passThreshold + additionalProperties = evalGraderScoreModel.additionalProperties.toMutableMap() + } + + /** The input text. This may include template strings. */ + fun input(input: List) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField>) = apply { + this.input = input.map { it.toMutableList() } + } + + /** + * Adds a single [ScoreModelGrader.Input] to [Builder.input]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addInput(input: ScoreModelGrader.Input) = apply { + this.input = + (this.input ?: JsonField.of(mutableListOf())).also { + checkKnown("input", it).add(input) + } + } + + /** The model to use for the evaluation. */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Sets the field to an arbitrary JSON value. * * It is usually unnecessary to call this method because the field defaults to the * following: @@ -1720,21 +2167,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The threshold for the score. */ - fun passThreshold(passThreshold: Double) = - passThreshold(JsonField.of(passThreshold)) - - /** - * Sets [Builder.passThreshold] to an arbitrary JSON value. - * - * You should usually call [Builder.passThreshold] with a well-typed [Double] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun passThreshold(passThreshold: JsonField) = apply { - this.passThreshold = passThreshold - } - /** The range of the score. Defaults to `[0, 1]`. */ fun range(range: List) = range(JsonField.of(range)) @@ -1766,6 +2198,21 @@ private constructor( this.samplingParams = samplingParams } + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1789,7 +2236,7 @@ private constructor( } /** - * Returns an immutable instance of [ScoreModel]. + * Returns an immutable instance of [EvalGraderScoreModel]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -1802,22 +2249,22 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): ScoreModel = - ScoreModel( + fun build(): EvalGraderScoreModel = + EvalGraderScoreModel( checkRequired("input", input).map { it.toImmutable() }, checkRequired("model", model), checkRequired("name", name), type, - passThreshold, (range ?: JsonMissing.of()).map { it.toImmutable() }, samplingParams, + passThreshold, additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): ScoreModel = apply { + fun validate(): EvalGraderScoreModel = apply { if (validated) { return@apply } @@ -1830,8 +2277,8 @@ private constructor( throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - passThreshold() range() + passThreshold() validated = true } @@ -1855,1003 +2302,25 @@ private constructor( (if (model.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + - (if (passThreshold.asKnown().isPresent) 1 else 0) + - (range.asKnown().getOrNull()?.size ?: 0) - - /** - * A message input to the model with a role indicating instruction following hierarchy. - * Instructions given with the `developer` or `system` role take precedence over - * instructions given with the `user` role. Messages with the `assistant` role are - * presumed to have been generated by the model in previous interactions. - */ - class Input - private constructor( - private val content: JsonField, - private val role: JsonField, - private val type: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("content") - @ExcludeMissing - content: JsonField = JsonMissing.of(), - @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(content, role, type, mutableMapOf()) - - /** - * Text inputs to the model - can contain template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun content(): Content = content.getRequired("content") - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun role(): Role = role.getRequired("role") - - /** - * The type of the message input. Always `message`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") - - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("content") - @ExcludeMissing - fun _content(): JsonField = content - - /** - * Returns the raw JSON value of [role]. - * - * Unlike [role], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Input]. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Input]. */ - class Builder internal constructor() { - - private var content: JsonField? = null - private var role: JsonField? = null - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(input: Input) = apply { - content = input.content - role = input.role - type = input.type - additionalProperties = input.additionalProperties.toMutableMap() - } - - /** Text inputs to the model - can contain template strings. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - - /** Alias for calling [content] with `Content.ofTextInput(textInput)`. */ - fun content(textInput: String) = content(Content.ofTextInput(textInput)) - - /** - * Alias for calling [content] with - * `Content.ofResponseInputText(responseInputText)`. - */ - fun content(responseInputText: ResponseInputText) = - content(Content.ofResponseInputText(responseInputText)) - - /** Alias for calling [content] with `Content.ofOutputText(outputText)`. */ - fun content(outputText: Content.OutputText) = - content(Content.ofOutputText(outputText)) - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - fun role(role: Role) = role(JsonField.of(role)) - - /** - * Sets [Builder.role] to an arbitrary JSON value. - * - * You should usually call [Builder.role] with a well-typed [Role] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun role(role: JsonField) = apply { this.role = role } - - /** The type of the message input. Always `message`. */ - fun type(type: Type) = type(JsonField.of(type)) - - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Input]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Input = - Input( - checkRequired("content", content), - checkRequired("role", role), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Input = apply { - if (validated) { - return@apply - } - - content().validate() - role().validate() - type().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (content.asKnown().getOrNull()?.validity() ?: 0) + - (role.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) - - /** Text inputs to the model - can contain template strings. */ - @JsonDeserialize(using = Content.Deserializer::class) - @JsonSerialize(using = Content.Serializer::class) - class Content - private constructor( - private val textInput: String? = null, - private val responseInputText: ResponseInputText? = null, - private val outputText: OutputText? = null, - private val _json: JsonValue? = null, - ) { - - /** A text input to the model. */ - fun textInput(): Optional = Optional.ofNullable(textInput) - - /** A text input to the model. */ - fun responseInputText(): Optional = - Optional.ofNullable(responseInputText) - - /** A text output from the model. */ - fun outputText(): Optional = Optional.ofNullable(outputText) - - fun isTextInput(): Boolean = textInput != null - - fun isResponseInputText(): Boolean = responseInputText != null - - fun isOutputText(): Boolean = outputText != null - - /** A text input to the model. */ - fun asTextInput(): String = textInput.getOrThrow("textInput") - - /** A text input to the model. */ - fun asResponseInputText(): ResponseInputText = - responseInputText.getOrThrow("responseInputText") - - /** A text output from the model. */ - fun asOutputText(): OutputText = outputText.getOrThrow("outputText") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - textInput != null -> visitor.visitTextInput(textInput) - responseInputText != null -> - visitor.visitResponseInputText(responseInputText) - outputText != null -> visitor.visitOutputText(outputText) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Content = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitTextInput(textInput: String) {} - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) { - responseInputText.validate() - } - - override fun visitOutputText(outputText: OutputText) { - outputText.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitTextInput(textInput: String) = 1 - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) = responseInputText.validity() - - override fun visitOutputText(outputText: OutputText) = - outputText.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && textInput == other.textInput && responseInputText == other.responseInputText && outputText == other.outputText /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(textInput, responseInputText, outputText) /* spotless:on */ - - override fun toString(): String = - when { - textInput != null -> "Content{textInput=$textInput}" - responseInputText != null -> - "Content{responseInputText=$responseInputText}" - outputText != null -> "Content{outputText=$outputText}" - _json != null -> "Content{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Content") - } - - companion object { - - /** A text input to the model. */ - @JvmStatic - fun ofTextInput(textInput: String) = Content(textInput = textInput) - - /** A text input to the model. */ - @JvmStatic - fun ofResponseInputText(responseInputText: ResponseInputText) = - Content(responseInputText = responseInputText) - - /** A text output from the model. */ - @JvmStatic - fun ofOutputText(outputText: OutputText) = Content(outputText = outputText) - } - - /** - * An interface that defines how to map each variant of [Content] to a value of - * type [T]. - */ - interface Visitor { - - /** A text input to the model. */ - fun visitTextInput(textInput: String): T - - /** A text input to the model. */ - fun visitResponseInputText(responseInputText: ResponseInputText): T - - /** A text output from the model. */ - fun visitOutputText(outputText: OutputText): T - - /** - * Maps an unknown variant of [Content] to a value of type [T]. - * - * An instance of [Content] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Content: $json") - } - } - - internal class Deserializer : BaseDeserializer(Content::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Content { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Content(responseInputText = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(outputText = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(textInput = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from array). - 0 -> Content(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Content::class) { - - override fun serialize( - value: Content, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.textInput != null -> generator.writeObject(value.textInput) - value.responseInputText != null -> - generator.writeObject(value.responseInputText) - value.outputText != null -> generator.writeObject(value.outputText) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Content") - } - } - } - - /** A text output from the model. */ - class OutputText - private constructor( - private val text: JsonField, - private val type: JsonValue, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("text") - @ExcludeMissing - text: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - ) : this(text, type, mutableMapOf()) - - /** - * The text output from the model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded - * with an unexpected value). - */ - fun text(): String = text.getRequired("text") - - /** - * The type of the output text. Always `output_text`. - * - * Expected to always return the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * However, this method can be useful for debugging and logging (e.g. if the - * server responded with an unexpected value). - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - - /** - * Returns the raw JSON value of [text]. - * - * Unlike [text], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [OutputText]. - * - * The following fields are required: - * ```java - * .text() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [OutputText]. */ - class Builder internal constructor() { - - private var text: JsonField? = null - private var type: JsonValue = JsonValue.from("output_text") - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(outputText: OutputText) = apply { - text = outputText.text - type = outputText.type - additionalProperties = - outputText.additionalProperties.toMutableMap() - } - - /** The text output from the model. */ - fun text(text: String) = text(JsonField.of(text)) - - /** - * Sets [Builder.text] to an arbitrary JSON value. - * - * You should usually call [Builder.text] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun text(text: JsonField) = apply { this.text = text } - - /** - * Sets the field to an arbitrary JSON value. - * - * It is usually unnecessary to call this method because the field - * defaults to the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonValue) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [OutputText]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - * - * The following fields are required: - * ```java - * .text() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): OutputText = - OutputText( - checkRequired("text", text), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): OutputText = apply { - if (validated) { - return@apply - } - - text() - _type().let { - if (it != JsonValue.from("output_text")) { - throw OpenAIInvalidDataException( - "'type' is invalid, received $it" - ) - } - } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (text.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("output_text")) 1 else 0 } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is OutputText && text == other.text && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(text, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "OutputText{text=$text, type=$type, additionalProperties=$additionalProperties}" - } - } - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - class Role @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val USER = of("user") - - @JvmField val ASSISTANT = of("assistant") - - @JvmField val SYSTEM = of("system") - - @JvmField val DEVELOPER = of("developer") - - @JvmStatic fun of(value: String) = Role(JsonField.of(value)) - } - - /** An enum containing [Role]'s known values. */ - enum class Known { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - } - - /** - * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Role] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - /** - * An enum member indicating that [Role] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - USER -> Value.USER - ASSISTANT -> Value.ASSISTANT - SYSTEM -> Value.SYSTEM - DEVELOPER -> Value.DEVELOPER - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - USER -> Known.USER - ASSISTANT -> Known.ASSISTANT - SYSTEM -> Known.SYSTEM - DEVELOPER -> Known.DEVELOPER - else -> throw OpenAIInvalidDataException("Unknown Role: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Role = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Role && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - /** The type of the message input. Always `message`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val MESSAGE = of("message") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - MESSAGE - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - MESSAGE, - /** - * An enum member indicating that [Type] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - MESSAGE -> Value.MESSAGE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - MESSAGE -> Known.MESSAGE - else -> throw OpenAIInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Type && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Input && content == other.content && role == other.role && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(content, role, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Input{content=$content, role=$role, type=$type, additionalProperties=$additionalProperties}" - } + (range.asKnown().getOrNull()?.size ?: 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && passThreshold == other.passThreshold && range == other.range && samplingParams == other.samplingParams && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && range == other.range && samplingParams == other.samplingParams && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(input, model, name, type, passThreshold, range, samplingParams, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(input, model, name, type, range, samplingParams, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "ScoreModel{input=$input, model=$model, name=$name, type=$type, passThreshold=$passThreshold, range=$range, samplingParams=$samplingParams, additionalProperties=$additionalProperties}" + "EvalGraderScoreModel{input=$input, model=$model, name=$name, type=$type, range=$range, samplingParams=$samplingParams, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateParams.kt index c5ea36945..d3556b083 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateParams.kt @@ -11,7 +11,6 @@ import com.openai.core.JsonField import com.openai.core.JsonMissing import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable @@ -24,13 +23,13 @@ import kotlin.jvm.optionals.getOrNull /** Update certain properties of an evaluation. */ class EvalUpdateParams private constructor( - private val evalId: String, + private val evalId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun evalId(): String = evalId + fun evalId(): Optional = Optional.ofNullable(evalId) /** * Set of 16 key-value pairs that can be attached to an object. This can be useful for storing @@ -77,14 +76,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [EvalUpdateParams]. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - */ + @JvmStatic fun none(): EvalUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [EvalUpdateParams]. */ @JvmStatic fun builder() = Builder() } @@ -104,7 +98,10 @@ private constructor( additionalQueryParams = evalUpdateParams.additionalQueryParams.toBuilder() } - fun evalId(evalId: String) = apply { this.evalId = evalId } + fun evalId(evalId: String?) = apply { this.evalId = evalId } + + /** Alias for calling [Builder.evalId] with `evalId.orElse(null)`. */ + fun evalId(evalId: Optional) = evalId(evalId.getOrNull()) /** * Sets the entire request body. @@ -270,17 +267,10 @@ private constructor( * Returns an immutable instance of [EvalUpdateParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): EvalUpdateParams = EvalUpdateParams( - checkRequired("evalId", evalId), + evalId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -291,7 +281,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> evalId + 0 -> evalId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateResponse.kt index db7ad9a1d..5d05142a1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateResponse.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalUpdateResponse.kt @@ -15,7 +15,6 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.BaseDeserializer import com.openai.core.BaseSerializer -import com.openai.core.Enum import com.openai.core.ExcludeMissing import com.openai.core.JsonField import com.openai.core.JsonMissing @@ -26,7 +25,11 @@ import com.openai.core.checkRequired import com.openai.core.getOrThrow import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException -import com.openai.models.responses.ResponseInputText +import com.openai.models.graders.gradermodels.LabelModelGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader import java.util.Collections import java.util.Objects import java.util.Optional @@ -388,34 +391,43 @@ private constructor( } /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofLabelModel(labelModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofLabelModelGrader(labelModelGrader)`. */ - fun addTestingCriterion(labelModel: EvalLabelModelGrader) = - addTestingCriterion(TestingCriterion.ofLabelModel(labelModel)) + fun addTestingCriterion(labelModelGrader: LabelModelGrader) = + addTestingCriterion(TestingCriterion.ofLabelModelGrader(labelModelGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofStringCheck(stringCheck)`. + * `TestingCriterion.ofStringCheckGrader(stringCheckGrader)`. */ - fun addTestingCriterion(stringCheck: EvalStringCheckGrader) = - addTestingCriterion(TestingCriterion.ofStringCheck(stringCheck)) + fun addTestingCriterion(stringCheckGrader: StringCheckGrader) = + addTestingCriterion(TestingCriterion.ofStringCheckGrader(stringCheckGrader)) /** * Alias for calling [addTestingCriterion] with - * `TestingCriterion.ofTextSimilarity(textSimilarity)`. + * `TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity)`. */ - fun addTestingCriterion(textSimilarity: EvalTextSimilarityGrader) = - addTestingCriterion(TestingCriterion.ofTextSimilarity(textSimilarity)) + fun addTestingCriterion( + evalGraderTextSimilarity: TestingCriterion.EvalGraderTextSimilarity + ) = + addTestingCriterion( + TestingCriterion.ofEvalGraderTextSimilarity(evalGraderTextSimilarity) + ) - /** Alias for calling [addTestingCriterion] with `TestingCriterion.ofPython(python)`. */ - fun addTestingCriterion(python: TestingCriterion.Python) = - addTestingCriterion(TestingCriterion.ofPython(python)) + /** + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderPython(evalGraderPython)`. + */ + fun addTestingCriterion(evalGraderPython: TestingCriterion.EvalGraderPython) = + addTestingCriterion(TestingCriterion.ofEvalGraderPython(evalGraderPython)) /** - * Alias for calling [addTestingCriterion] with `TestingCriterion.ofScoreModel(scoreModel)`. + * Alias for calling [addTestingCriterion] with + * `TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)`. */ - fun addTestingCriterion(scoreModel: TestingCriterion.ScoreModel) = - addTestingCriterion(TestingCriterion.ofScoreModel(scoreModel)) + fun addTestingCriterion(evalGraderScoreModel: TestingCriterion.EvalGraderScoreModel) = + addTestingCriterion(TestingCriterion.ofEvalGraderScoreModel(evalGraderScoreModel)) fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -860,11 +872,11 @@ private constructor( @JsonSerialize(using = TestingCriterion.Serializer::class) class TestingCriterion private constructor( - private val labelModel: EvalLabelModelGrader? = null, - private val stringCheck: EvalStringCheckGrader? = null, - private val textSimilarity: EvalTextSimilarityGrader? = null, - private val python: Python? = null, - private val scoreModel: ScoreModel? = null, + private val labelModelGrader: LabelModelGrader? = null, + private val stringCheckGrader: StringCheckGrader? = null, + private val evalGraderTextSimilarity: EvalGraderTextSimilarity? = null, + private val evalGraderPython: EvalGraderPython? = null, + private val evalGraderScoreModel: EvalGraderScoreModel? = null, private val _json: JsonValue? = null, ) { @@ -872,65 +884,71 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun labelModel(): Optional = Optional.ofNullable(labelModel) + fun labelModelGrader(): Optional = Optional.ofNullable(labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + fun stringCheckGrader(): Optional = + Optional.ofNullable(stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun textSimilarity(): Optional = - Optional.ofNullable(textSimilarity) + fun evalGraderTextSimilarity(): Optional = + Optional.ofNullable(evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - fun python(): Optional = Optional.ofNullable(python) + fun evalGraderPython(): Optional = Optional.ofNullable(evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + fun evalGraderScoreModel(): Optional = + Optional.ofNullable(evalGraderScoreModel) - fun isLabelModel(): Boolean = labelModel != null + fun isLabelModelGrader(): Boolean = labelModelGrader != null - fun isStringCheck(): Boolean = stringCheck != null + fun isStringCheckGrader(): Boolean = stringCheckGrader != null - fun isTextSimilarity(): Boolean = textSimilarity != null + fun isEvalGraderTextSimilarity(): Boolean = evalGraderTextSimilarity != null - fun isPython(): Boolean = python != null + fun isEvalGraderPython(): Boolean = evalGraderPython != null - fun isScoreModel(): Boolean = scoreModel != null + fun isEvalGraderScoreModel(): Boolean = evalGraderScoreModel != null /** * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun asLabelModel(): EvalLabelModelGrader = labelModel.getOrThrow("labelModel") + fun asLabelModelGrader(): LabelModelGrader = labelModelGrader.getOrThrow("labelModelGrader") /** * A StringCheckGrader object that performs a string comparison between input and reference * using a specified operation. */ - fun asStringCheck(): EvalStringCheckGrader = stringCheck.getOrThrow("stringCheck") + fun asStringCheckGrader(): StringCheckGrader = + stringCheckGrader.getOrThrow("stringCheckGrader") /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun asTextSimilarity(): EvalTextSimilarityGrader = - textSimilarity.getOrThrow("textSimilarity") + fun asEvalGraderTextSimilarity(): EvalGraderTextSimilarity = + evalGraderTextSimilarity.getOrThrow("evalGraderTextSimilarity") /** A PythonGrader object that runs a python script on the input. */ - fun asPython(): Python = python.getOrThrow("python") + fun asEvalGraderPython(): EvalGraderPython = evalGraderPython.getOrThrow("evalGraderPython") /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun asScoreModel(): ScoreModel = scoreModel.getOrThrow("scoreModel") + fun asEvalGraderScoreModel(): EvalGraderScoreModel = + evalGraderScoreModel.getOrThrow("evalGraderScoreModel") fun _json(): Optional = Optional.ofNullable(_json) fun accept(visitor: Visitor): T = when { - labelModel != null -> visitor.visitLabelModel(labelModel) - stringCheck != null -> visitor.visitStringCheck(stringCheck) - textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) - python != null -> visitor.visitPython(python) - scoreModel != null -> visitor.visitScoreModel(scoreModel) + labelModelGrader != null -> visitor.visitLabelModelGrader(labelModelGrader) + stringCheckGrader != null -> visitor.visitStringCheckGrader(stringCheckGrader) + evalGraderTextSimilarity != null -> + visitor.visitEvalGraderTextSimilarity(evalGraderTextSimilarity) + evalGraderPython != null -> visitor.visitEvalGraderPython(evalGraderPython) + evalGraderScoreModel != null -> + visitor.visitEvalGraderScoreModel(evalGraderScoreModel) else -> visitor.unknown(_json) } @@ -943,24 +961,28 @@ private constructor( accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) { - labelModel.validate() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) { + labelModelGrader.validate() } - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) { - stringCheck.validate() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) { + stringCheckGrader.validate() } - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) { - textSimilarity.validate() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) { + evalGraderTextSimilarity.validate() } - override fun visitPython(python: Python) { - python.validate() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) { + evalGraderPython.validate() } - override fun visitScoreModel(scoreModel: ScoreModel) { - scoreModel.validate() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) { + evalGraderScoreModel.validate() } } ) @@ -985,18 +1007,22 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitLabelModel(labelModel: EvalLabelModelGrader) = - labelModel.validity() + override fun visitLabelModelGrader(labelModelGrader: LabelModelGrader) = + labelModelGrader.validity() - override fun visitStringCheck(stringCheck: EvalStringCheckGrader) = - stringCheck.validity() + override fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader) = + stringCheckGrader.validity() - override fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - textSimilarity.validity() + override fun visitEvalGraderTextSimilarity( + evalGraderTextSimilarity: EvalGraderTextSimilarity + ) = evalGraderTextSimilarity.validity() - override fun visitPython(python: Python) = python.validity() + override fun visitEvalGraderPython(evalGraderPython: EvalGraderPython) = + evalGraderPython.validity() - override fun visitScoreModel(scoreModel: ScoreModel) = scoreModel.validity() + override fun visitEvalGraderScoreModel( + evalGraderScoreModel: EvalGraderScoreModel + ) = evalGraderScoreModel.validity() override fun unknown(json: JsonValue?) = 0 } @@ -1007,18 +1033,21 @@ private constructor( return true } - return /* spotless:off */ other is TestingCriterion && labelModel == other.labelModel && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel /* spotless:on */ + return /* spotless:off */ other is TestingCriterion && labelModelGrader == other.labelModelGrader && stringCheckGrader == other.stringCheckGrader && evalGraderTextSimilarity == other.evalGraderTextSimilarity && evalGraderPython == other.evalGraderPython && evalGraderScoreModel == other.evalGraderScoreModel /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModel, stringCheck, textSimilarity, python, scoreModel) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(labelModelGrader, stringCheckGrader, evalGraderTextSimilarity, evalGraderPython, evalGraderScoreModel) /* spotless:on */ override fun toString(): String = when { - labelModel != null -> "TestingCriterion{labelModel=$labelModel}" - stringCheck != null -> "TestingCriterion{stringCheck=$stringCheck}" - textSimilarity != null -> "TestingCriterion{textSimilarity=$textSimilarity}" - python != null -> "TestingCriterion{python=$python}" - scoreModel != null -> "TestingCriterion{scoreModel=$scoreModel}" + labelModelGrader != null -> "TestingCriterion{labelModelGrader=$labelModelGrader}" + stringCheckGrader != null -> + "TestingCriterion{stringCheckGrader=$stringCheckGrader}" + evalGraderTextSimilarity != null -> + "TestingCriterion{evalGraderTextSimilarity=$evalGraderTextSimilarity}" + evalGraderPython != null -> "TestingCriterion{evalGraderPython=$evalGraderPython}" + evalGraderScoreModel != null -> + "TestingCriterion{evalGraderScoreModel=$evalGraderScoreModel}" _json != null -> "TestingCriterion{_unknown=$_json}" else -> throw IllegalStateException("Invalid TestingCriterion") } @@ -1030,28 +1059,31 @@ private constructor( * evaluation. */ @JvmStatic - fun ofLabelModel(labelModel: EvalLabelModelGrader) = - TestingCriterion(labelModel = labelModel) + fun ofLabelModelGrader(labelModelGrader: LabelModelGrader) = + TestingCriterion(labelModelGrader = labelModelGrader) /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ @JvmStatic - fun ofStringCheck(stringCheck: EvalStringCheckGrader) = - TestingCriterion(stringCheck = stringCheck) + fun ofStringCheckGrader(stringCheckGrader: StringCheckGrader) = + TestingCriterion(stringCheckGrader = stringCheckGrader) /** A TextSimilarityGrader object which grades text based on similarity metrics. */ @JvmStatic - fun ofTextSimilarity(textSimilarity: EvalTextSimilarityGrader) = - TestingCriterion(textSimilarity = textSimilarity) + fun ofEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity) = + TestingCriterion(evalGraderTextSimilarity = evalGraderTextSimilarity) /** A PythonGrader object that runs a python script on the input. */ - @JvmStatic fun ofPython(python: Python) = TestingCriterion(python = python) + @JvmStatic + fun ofEvalGraderPython(evalGraderPython: EvalGraderPython) = + TestingCriterion(evalGraderPython = evalGraderPython) /** A ScoreModelGrader object that uses a model to assign a score to the input. */ @JvmStatic - fun ofScoreModel(scoreModel: ScoreModel) = TestingCriterion(scoreModel = scoreModel) + fun ofEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel) = + TestingCriterion(evalGraderScoreModel = evalGraderScoreModel) } /** @@ -1064,22 +1096,22 @@ private constructor( * A LabelModelGrader object which uses a model to assign labels to each item in the * evaluation. */ - fun visitLabelModel(labelModel: EvalLabelModelGrader): T + fun visitLabelModelGrader(labelModelGrader: LabelModelGrader): T /** * A StringCheckGrader object that performs a string comparison between input and * reference using a specified operation. */ - fun visitStringCheck(stringCheck: EvalStringCheckGrader): T + fun visitStringCheckGrader(stringCheckGrader: StringCheckGrader): T /** A TextSimilarityGrader object which grades text based on similarity metrics. */ - fun visitTextSimilarity(textSimilarity: EvalTextSimilarityGrader): T + fun visitEvalGraderTextSimilarity(evalGraderTextSimilarity: EvalGraderTextSimilarity): T /** A PythonGrader object that runs a python script on the input. */ - fun visitPython(python: Python): T + fun visitEvalGraderPython(evalGraderPython: EvalGraderPython): T /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - fun visitScoreModel(scoreModel: ScoreModel): T + fun visitEvalGraderScoreModel(evalGraderScoreModel: EvalGraderScoreModel): T /** * Maps an unknown variant of [TestingCriterion] to a value of type [T]. @@ -1100,37 +1132,38 @@ private constructor( override fun ObjectCodec.deserialize(node: JsonNode): TestingCriterion { val json = JsonValue.fromJsonNode(node) - val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() - when (type) { - "label_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(labelModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "string_check" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(stringCheck = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "text_similarity" -> { - return tryDeserialize(node, jacksonTypeRef()) - ?.let { TestingCriterion(textSimilarity = it, _json = json) } - ?: TestingCriterion(_json = json) - } - "python" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(python = it, _json = json) - } ?: TestingCriterion(_json = json) - } - "score_model" -> { - return tryDeserialize(node, jacksonTypeRef())?.let { - TestingCriterion(scoreModel = it, _json = json) - } ?: TestingCriterion(_json = json) - } + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(labelModelGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(stringCheckGrader = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderTextSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderPython = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + TestingCriterion(evalGraderScoreModel = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> TestingCriterion(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() } - - return TestingCriterion(_json = json) } } @@ -1142,42 +1175,77 @@ private constructor( provider: SerializerProvider, ) { when { - value.labelModel != null -> generator.writeObject(value.labelModel) - value.stringCheck != null -> generator.writeObject(value.stringCheck) - value.textSimilarity != null -> generator.writeObject(value.textSimilarity) - value.python != null -> generator.writeObject(value.python) - value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.labelModelGrader != null -> generator.writeObject(value.labelModelGrader) + value.stringCheckGrader != null -> + generator.writeObject(value.stringCheckGrader) + value.evalGraderTextSimilarity != null -> + generator.writeObject(value.evalGraderTextSimilarity) + value.evalGraderPython != null -> generator.writeObject(value.evalGraderPython) + value.evalGraderScoreModel != null -> + generator.writeObject(value.evalGraderScoreModel) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid TestingCriterion") } } } - /** A PythonGrader object that runs a python script on the input. */ - class Python + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + class EvalGraderTextSimilarity private constructor( + private val evaluationMetric: JsonField, + private val input: JsonField, private val name: JsonField, - private val source: JsonField, + private val reference: JsonField, private val type: JsonValue, - private val imageTag: JsonField, private val passThreshold: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( + @JsonProperty("evaluation_metric") + @ExcludeMissing + evaluationMetric: JsonField = + JsonMissing.of(), + @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - @JsonProperty("source") + @JsonProperty("reference") @ExcludeMissing - source: JsonField = JsonMissing.of(), + reference: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - @JsonProperty("image_tag") - @ExcludeMissing - imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) + ) : this(evaluationMetric, input, name, reference, type, passThreshold, mutableMapOf()) + + fun toTextSimilarityGrader(): TextSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(evaluationMetric) + .input(input) + .name(name) + .reference(reference) + .type(type) + .build() + + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun evaluationMetric(): TextSimilarityGrader.EvaluationMetric = + evaluationMetric.getRequired("evaluation_metric") + + /** + * The text being graded. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): String = input.getRequired("input") /** * The name of the grader. @@ -1189,20 +1257,20 @@ private constructor( fun name(): String = name.getRequired("name") /** - * The source code of the python script. + * The text being graded against. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun source(): String = source.getRequired("source") + fun reference(): String = reference.getRequired("reference") /** - * The object type, which is always `python`. + * The type of grader. * * Expected to always return the following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1211,42 +1279,48 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The image tag to use for the python script. + * The threshold for the score. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun imageTag(): Optional = imageTag.getOptional("image_tag") + fun passThreshold(): Double = passThreshold.getRequired("pass_threshold") /** - * The threshold for the score. + * Returns the raw JSON value of [evaluationMetric]. * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * Unlike [evaluationMetric], this method doesn't throw if the JSON field has an + * unexpected type. */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + @JsonProperty("evaluation_metric") + @ExcludeMissing + fun _evaluationMetric(): JsonField = + evaluationMetric /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [input]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input /** - * Returns the raw JSON value of [source]. + * Returns the raw JSON value of [name]. * - * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [imageTag]. + * Returns the raw JSON value of [reference]. * - * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * Unlike [reference], this method doesn't throw if the JSON field has an unexpected * type. */ - @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag + @JsonProperty("reference") + @ExcludeMissing + fun _reference(): JsonField = reference /** * Returns the raw JSON value of [passThreshold]. @@ -1273,37 +1347,75 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [Python]. + * Returns a mutable builder for constructing an instance of + * [EvalGraderTextSimilarity]. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [Python]. */ + /** A builder for [EvalGraderTextSimilarity]. */ class Builder internal constructor() { + private var evaluationMetric: JsonField? = + null + private var input: JsonField? = null private var name: JsonField? = null - private var source: JsonField? = null - private var type: JsonValue = JsonValue.from("python") - private var imageTag: JsonField = JsonMissing.of() - private var passThreshold: JsonField = JsonMissing.of() + private var reference: JsonField? = null + private var type: JsonValue = JsonValue.from("text_similarity") + private var passThreshold: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(python: Python) = apply { - name = python.name - source = python.source - type = python.type - imageTag = python.imageTag - passThreshold = python.passThreshold - additionalProperties = python.additionalProperties.toMutableMap() + internal fun from(evalGraderTextSimilarity: EvalGraderTextSimilarity) = apply { + evaluationMetric = evalGraderTextSimilarity.evaluationMetric + input = evalGraderTextSimilarity.input + name = evalGraderTextSimilarity.name + reference = evalGraderTextSimilarity.reference + type = evalGraderTextSimilarity.type + passThreshold = evalGraderTextSimilarity.passThreshold + additionalProperties = + evalGraderTextSimilarity.additionalProperties.toMutableMap() } + /** + * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, + * `rouge_1`, `rouge_2`, `rouge_3`, `rouge_4`, `rouge_5`, or `rouge_l`. + */ + fun evaluationMetric(evaluationMetric: TextSimilarityGrader.EvaluationMetric) = + evaluationMetric(JsonField.of(evaluationMetric)) + + /** + * Sets [Builder.evaluationMetric] to an arbitrary JSON value. + * + * You should usually call [Builder.evaluationMetric] with a well-typed + * [TextSimilarityGrader.EvaluationMetric] value instead. This method is primarily + * for setting the field to an undocumented or not yet supported value. + */ + fun evaluationMetric( + evaluationMetric: JsonField + ) = apply { this.evaluationMetric = evaluationMetric } + + /** The text being graded. */ + fun input(input: String) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun input(input: JsonField) = apply { this.input = input } + /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1316,17 +1428,17 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } - /** The source code of the python script. */ - fun source(source: String) = source(JsonField.of(source)) + /** The text being graded against. */ + fun reference(reference: String) = reference(JsonField.of(reference)) /** - * Sets [Builder.source] to an arbitrary JSON value. + * Sets [Builder.reference] to an arbitrary JSON value. * - * You should usually call [Builder.source] with a well-typed [String] value + * You should usually call [Builder.reference] with a well-typed [String] value * instead. This method is primarily for setting the field to an undocumented or not * yet supported value. */ - fun source(source: JsonField) = apply { this.source = source } + fun reference(reference: JsonField) = apply { this.reference = reference } /** * Sets the field to an arbitrary JSON value. @@ -1334,7 +1446,7 @@ private constructor( * It is usually unnecessary to call this method because the field defaults to the * following: * ```java - * JsonValue.from("python") + * JsonValue.from("text_similarity") * ``` * * This method is primarily for setting the field to an undocumented or not yet @@ -1342,18 +1454,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The image tag to use for the python script. */ - fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) - - /** - * Sets [Builder.imageTag] to an arbitrary JSON value. - * - * You should usually call [Builder.imageTag] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } - /** The threshold for the score. */ fun passThreshold(passThreshold: Double) = passThreshold(JsonField.of(passThreshold)) @@ -1392,44 +1492,49 @@ private constructor( } /** - * Returns an immutable instance of [Python]. + * Returns an immutable instance of [EvalGraderTextSimilarity]. * * Further updates to this [Builder] will not mutate the returned instance. * * The following fields are required: * ```java + * .evaluationMetric() + * .input() * .name() - * .source() + * .reference() + * .passThreshold() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): Python = - Python( + fun build(): EvalGraderTextSimilarity = + EvalGraderTextSimilarity( + checkRequired("evaluationMetric", evaluationMetric), + checkRequired("input", input), checkRequired("name", name), - checkRequired("source", source), + checkRequired("reference", reference), type, - imageTag, - passThreshold, + checkRequired("passThreshold", passThreshold), additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): Python = apply { + fun validate(): EvalGraderTextSimilarity = apply { if (validated) { return@apply } + evaluationMetric().validate() + input() name() - source() + reference() _type().let { - if (it != JsonValue.from("python")) { + if (it != JsonValue.from("text_similarity")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - imageTag() passThreshold() validated = true } @@ -1450,10 +1555,11 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (name.asKnown().isPresent) 1 else 0) + - (if (source.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("python")) 1 else 0 } + - (if (imageTag.asKnown().isPresent) 1 else 0) + + (evaluationMetric.asKnown().getOrNull()?.validity() ?: 0) + + (if (input.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (reference.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -1461,84 +1567,77 @@ private constructor( return true } - return /* spotless:off */ other is Python && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderTextSimilarity && evaluationMetric == other.evaluationMetric && input == other.input && name == other.name && reference == other.reference && type == other.type && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, name, reference, type, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Python{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + "EvalGraderTextSimilarity{evaluationMetric=$evaluationMetric, input=$input, name=$name, reference=$reference, type=$type, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } - /** A ScoreModelGrader object that uses a model to assign a score to the input. */ - class ScoreModel + /** A PythonGrader object that runs a python script on the input. */ + class EvalGraderPython private constructor( - private val input: JsonField>, - private val model: JsonField, private val name: JsonField, + private val source: JsonField, private val type: JsonValue, + private val imageTag: JsonField, private val passThreshold: JsonField, - private val range: JsonField>, - private val samplingParams: JsonValue, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("input") - @ExcludeMissing - input: JsonField> = JsonMissing.of(), - @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("source") + @ExcludeMissing + source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("image_tag") + @ExcludeMissing + imageTag: JsonField = JsonMissing.of(), @JsonProperty("pass_threshold") @ExcludeMissing passThreshold: JsonField = JsonMissing.of(), - @JsonProperty("range") - @ExcludeMissing - range: JsonField> = JsonMissing.of(), - @JsonProperty("sampling_params") - @ExcludeMissing - samplingParams: JsonValue = JsonMissing.of(), - ) : this(input, model, name, type, passThreshold, range, samplingParams, mutableMapOf()) + ) : this(name, source, type, imageTag, passThreshold, mutableMapOf()) - /** - * The input text. This may include template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun input(): List = input.getRequired("input") + fun toPythonGrader(): PythonGrader = + PythonGrader.builder() + .name(name) + .source(source) + .type(type) + .imageTag(imageTag) + .build() /** - * The model to use for the evaluation. + * The name of the grader. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun model(): String = model.getRequired("model") + fun name(): String = name.getRequired("name") /** - * The name of the grader. + * The source code of the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected * value). */ - fun name(): String = name.getRequired("name") + fun source(): String = source.getRequired("source") /** - * The object type, which is always `score_model`. + * The object type, which is always `python`. * * Expected to always return the following: * ```java - * JsonValue.from("score_model") + * JsonValue.from("python") * ``` * * However, this method can be useful for debugging and logging (e.g. if the server @@ -1547,46 +1646,42 @@ private constructor( @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type /** - * The threshold for the score. + * The image tag to use for the python script. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + fun imageTag(): Optional = imageTag.getOptional("image_tag") /** - * The range of the score. Defaults to `[0, 1]`. + * The threshold for the score. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun range(): Optional> = range.getOptional("range") - - /** The sampling parameters for the model. */ - @JsonProperty("sampling_params") - @ExcludeMissing - fun _samplingParams(): JsonValue = samplingParams + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") /** - * Returns the raw JSON value of [input]. + * Returns the raw JSON value of [name]. * - * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("input") @ExcludeMissing fun _input(): JsonField> = input + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** - * Returns the raw JSON value of [model]. + * Returns the raw JSON value of [source]. * - * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source /** - * Returns the raw JSON value of [name]. + * Returns the raw JSON value of [imageTag]. * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag /** * Returns the raw JSON value of [passThreshold]. @@ -1598,13 +1693,6 @@ private constructor( @ExcludeMissing fun _passThreshold(): JsonField = passThreshold - /** - * Returns the raw JSON value of [range]. - * - * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -1620,80 +1708,37 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [ScoreModel]. + * Returns a mutable builder for constructing an instance of [EvalGraderPython]. * * The following fields are required: * ```java - * .input() - * .model() * .name() + * .source() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [ScoreModel]. */ + /** A builder for [EvalGraderPython]. */ class Builder internal constructor() { - private var input: JsonField>? = null - private var model: JsonField? = null private var name: JsonField? = null - private var type: JsonValue = JsonValue.from("score_model") + private var source: JsonField? = null + private var type: JsonValue = JsonValue.from("python") + private var imageTag: JsonField = JsonMissing.of() private var passThreshold: JsonField = JsonMissing.of() - private var range: JsonField>? = null - private var samplingParams: JsonValue = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(scoreModel: ScoreModel) = apply { - input = scoreModel.input.map { it.toMutableList() } - model = scoreModel.model - name = scoreModel.name - type = scoreModel.type - passThreshold = scoreModel.passThreshold - range = scoreModel.range.map { it.toMutableList() } - samplingParams = scoreModel.samplingParams - additionalProperties = scoreModel.additionalProperties.toMutableMap() - } - - /** The input text. This may include template strings. */ - fun input(input: List) = input(JsonField.of(input)) - - /** - * Sets [Builder.input] to an arbitrary JSON value. - * - * You should usually call [Builder.input] with a well-typed `List` value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun input(input: JsonField>) = apply { - this.input = input.map { it.toMutableList() } - } - - /** - * Adds a single [Input] to [Builder.input]. - * - * @throws IllegalStateException if the field was previously set to a non-list. - */ - fun addInput(input: Input) = apply { - this.input = - (this.input ?: JsonField.of(mutableListOf())).also { - checkKnown("input", it).add(input) - } + internal fun from(evalGraderPython: EvalGraderPython) = apply { + name = evalGraderPython.name + source = evalGraderPython.source + type = evalGraderPython.type + imageTag = evalGraderPython.imageTag + passThreshold = evalGraderPython.passThreshold + additionalProperties = evalGraderPython.additionalProperties.toMutableMap() } - /** The model to use for the evaluation. */ - fun model(model: String) = model(JsonField.of(model)) - - /** - * Sets [Builder.model] to an arbitrary JSON value. - * - * You should usually call [Builder.model] with a well-typed [String] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun model(model: JsonField) = apply { this.model = model } - /** The name of the grader. */ fun name(name: String) = name(JsonField.of(name)) @@ -1706,8 +1751,410 @@ private constructor( */ fun name(name: JsonField) = apply { this.name = name } + /** The source code of the python script. */ + fun source(source: String) = source(JsonField.of(source)) + /** - * Sets the field to an arbitrary JSON value. + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("python") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The image tag to use for the python script. */ + fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) + + /** + * Sets [Builder.imageTag] to an arbitrary JSON value. + * + * You should usually call [Builder.imageTag] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } + + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [EvalGraderPython]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .source() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): EvalGraderPython = + EvalGraderPython( + checkRequired("name", name), + checkRequired("source", source), + type, + imageTag, + passThreshold, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): EvalGraderPython = apply { + if (validated) { + return@apply + } + + name() + source() + _type().let { + if (it != JsonValue.from("python")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + imageTag() + passThreshold() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (if (source.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("python")) 1 else 0 } + + (if (imageTag.asKnown().isPresent) 1 else 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is EvalGraderPython && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, passThreshold, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "EvalGraderPython{name=$name, source=$source, type=$type, imageTag=$imageTag, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" + } + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + class EvalGraderScoreModel + private constructor( + private val input: JsonField>, + private val model: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val range: JsonField>, + private val samplingParams: JsonValue, + private val passThreshold: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("input") + @ExcludeMissing + input: JsonField> = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("range") + @ExcludeMissing + range: JsonField> = JsonMissing.of(), + @JsonProperty("sampling_params") + @ExcludeMissing + samplingParams: JsonValue = JsonMissing.of(), + @JsonProperty("pass_threshold") + @ExcludeMissing + passThreshold: JsonField = JsonMissing.of(), + ) : this(input, model, name, type, range, samplingParams, passThreshold, mutableMapOf()) + + fun toScoreModelGrader(): ScoreModelGrader = + ScoreModelGrader.builder() + .input(input) + .model(model) + .name(name) + .type(type) + .range(range) + .samplingParams(samplingParams) + .build() + + /** + * The input text. This may include template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun input(): List = input.getRequired("input") + + /** + * The model to use for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun model(): String = model.getRequired("model") + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") + + /** + * The object type, which is always `score_model`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The range of the score. Defaults to `[0, 1]`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun range(): Optional> = range.getOptional("range") + + /** The sampling parameters for the model. */ + @JsonProperty("sampling_params") + @ExcludeMissing + fun _samplingParams(): JsonValue = samplingParams + + /** + * The threshold for the score. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun passThreshold(): Optional = passThreshold.getOptional("pass_threshold") + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") + @ExcludeMissing + fun _input(): JsonField> = input + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [range]. + * + * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range + + /** + * Returns the raw JSON value of [passThreshold]. + * + * Unlike [passThreshold], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pass_threshold") + @ExcludeMissing + fun _passThreshold(): JsonField = passThreshold + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [EvalGraderScoreModel]. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [EvalGraderScoreModel]. */ + class Builder internal constructor() { + + private var input: JsonField>? = null + private var model: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("score_model") + private var range: JsonField>? = null + private var samplingParams: JsonValue = JsonMissing.of() + private var passThreshold: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(evalGraderScoreModel: EvalGraderScoreModel) = apply { + input = evalGraderScoreModel.input.map { it.toMutableList() } + model = evalGraderScoreModel.model + name = evalGraderScoreModel.name + type = evalGraderScoreModel.type + range = evalGraderScoreModel.range.map { it.toMutableList() } + samplingParams = evalGraderScoreModel.samplingParams + passThreshold = evalGraderScoreModel.passThreshold + additionalProperties = evalGraderScoreModel.additionalProperties.toMutableMap() + } + + /** The input text. This may include template strings. */ + fun input(input: List) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed + * `List` value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun input(input: JsonField>) = apply { + this.input = input.map { it.toMutableList() } + } + + /** + * Adds a single [ScoreModelGrader.Input] to [Builder.input]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addInput(input: ScoreModelGrader.Input) = apply { + this.input = + (this.input ?: JsonField.of(mutableListOf())).also { + checkKnown("input", it).add(input) + } + } + + /** The model to use for the evaluation. */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Sets the field to an arbitrary JSON value. * * It is usually unnecessary to call this method because the field defaults to the * following: @@ -1720,21 +2167,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The threshold for the score. */ - fun passThreshold(passThreshold: Double) = - passThreshold(JsonField.of(passThreshold)) - - /** - * Sets [Builder.passThreshold] to an arbitrary JSON value. - * - * You should usually call [Builder.passThreshold] with a well-typed [Double] value - * instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. - */ - fun passThreshold(passThreshold: JsonField) = apply { - this.passThreshold = passThreshold - } - /** The range of the score. Defaults to `[0, 1]`. */ fun range(range: List) = range(JsonField.of(range)) @@ -1766,6 +2198,21 @@ private constructor( this.samplingParams = samplingParams } + /** The threshold for the score. */ + fun passThreshold(passThreshold: Double) = + passThreshold(JsonField.of(passThreshold)) + + /** + * Sets [Builder.passThreshold] to an arbitrary JSON value. + * + * You should usually call [Builder.passThreshold] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun passThreshold(passThreshold: JsonField) = apply { + this.passThreshold = passThreshold + } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1789,7 +2236,7 @@ private constructor( } /** - * Returns an immutable instance of [ScoreModel]. + * Returns an immutable instance of [EvalGraderScoreModel]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -1802,22 +2249,22 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): ScoreModel = - ScoreModel( + fun build(): EvalGraderScoreModel = + EvalGraderScoreModel( checkRequired("input", input).map { it.toImmutable() }, checkRequired("model", model), checkRequired("name", name), type, - passThreshold, (range ?: JsonMissing.of()).map { it.toImmutable() }, samplingParams, + passThreshold, additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): ScoreModel = apply { + fun validate(): EvalGraderScoreModel = apply { if (validated) { return@apply } @@ -1830,8 +2277,8 @@ private constructor( throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - passThreshold() range() + passThreshold() validated = true } @@ -1855,1003 +2302,25 @@ private constructor( (if (model.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + - (if (passThreshold.asKnown().isPresent) 1 else 0) + - (range.asKnown().getOrNull()?.size ?: 0) - - /** - * A message input to the model with a role indicating instruction following hierarchy. - * Instructions given with the `developer` or `system` role take precedence over - * instructions given with the `user` role. Messages with the `assistant` role are - * presumed to have been generated by the model in previous interactions. - */ - class Input - private constructor( - private val content: JsonField, - private val role: JsonField, - private val type: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("content") - @ExcludeMissing - content: JsonField = JsonMissing.of(), - @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(content, role, type, mutableMapOf()) - - /** - * Text inputs to the model - can contain template strings. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun content(): Content = content.getRequired("content") - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). - */ - fun role(): Role = role.getRequired("role") - - /** - * The type of the message input. Always `message`. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun type(): Optional = type.getOptional("type") - - /** - * Returns the raw JSON value of [content]. - * - * Unlike [content], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("content") - @ExcludeMissing - fun _content(): JsonField = content - - /** - * Returns the raw JSON value of [role]. - * - * Unlike [role], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - - /** - * Returns the raw JSON value of [type]. - * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Input]. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Input]. */ - class Builder internal constructor() { - - private var content: JsonField? = null - private var role: JsonField? = null - private var type: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(input: Input) = apply { - content = input.content - role = input.role - type = input.type - additionalProperties = input.additionalProperties.toMutableMap() - } - - /** Text inputs to the model - can contain template strings. */ - fun content(content: Content) = content(JsonField.of(content)) - - /** - * Sets [Builder.content] to an arbitrary JSON value. - * - * You should usually call [Builder.content] with a well-typed [Content] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun content(content: JsonField) = apply { this.content = content } - - /** Alias for calling [content] with `Content.ofTextInput(textInput)`. */ - fun content(textInput: String) = content(Content.ofTextInput(textInput)) - - /** - * Alias for calling [content] with - * `Content.ofResponseInputText(responseInputText)`. - */ - fun content(responseInputText: ResponseInputText) = - content(Content.ofResponseInputText(responseInputText)) - - /** Alias for calling [content] with `Content.ofOutputText(outputText)`. */ - fun content(outputText: Content.OutputText) = - content(Content.ofOutputText(outputText)) - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - fun role(role: Role) = role(JsonField.of(role)) - - /** - * Sets [Builder.role] to an arbitrary JSON value. - * - * You should usually call [Builder.role] with a well-typed [Role] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun role(role: JsonField) = apply { this.role = role } - - /** The type of the message input. Always `message`. */ - fun type(type: Type) = type(JsonField.of(type)) - - /** - * Sets [Builder.type] to an arbitrary JSON value. - * - * You should usually call [Builder.type] with a well-typed [Type] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonField) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Input]. - * - * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .content() - * .role() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): Input = - Input( - checkRequired("content", content), - checkRequired("role", role), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Input = apply { - if (validated) { - return@apply - } - - content().validate() - role().validate() - type().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (content.asKnown().getOrNull()?.validity() ?: 0) + - (role.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) - - /** Text inputs to the model - can contain template strings. */ - @JsonDeserialize(using = Content.Deserializer::class) - @JsonSerialize(using = Content.Serializer::class) - class Content - private constructor( - private val textInput: String? = null, - private val responseInputText: ResponseInputText? = null, - private val outputText: OutputText? = null, - private val _json: JsonValue? = null, - ) { - - /** A text input to the model. */ - fun textInput(): Optional = Optional.ofNullable(textInput) - - /** A text input to the model. */ - fun responseInputText(): Optional = - Optional.ofNullable(responseInputText) - - /** A text output from the model. */ - fun outputText(): Optional = Optional.ofNullable(outputText) - - fun isTextInput(): Boolean = textInput != null - - fun isResponseInputText(): Boolean = responseInputText != null - - fun isOutputText(): Boolean = outputText != null - - /** A text input to the model. */ - fun asTextInput(): String = textInput.getOrThrow("textInput") - - /** A text input to the model. */ - fun asResponseInputText(): ResponseInputText = - responseInputText.getOrThrow("responseInputText") - - /** A text output from the model. */ - fun asOutputText(): OutputText = outputText.getOrThrow("outputText") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - textInput != null -> visitor.visitTextInput(textInput) - responseInputText != null -> - visitor.visitResponseInputText(responseInputText) - outputText != null -> visitor.visitOutputText(outputText) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Content = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitTextInput(textInput: String) {} - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) { - responseInputText.validate() - } - - override fun visitOutputText(outputText: OutputText) { - outputText.validate() - } - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitTextInput(textInput: String) = 1 - - override fun visitResponseInputText( - responseInputText: ResponseInputText - ) = responseInputText.validity() - - override fun visitOutputText(outputText: OutputText) = - outputText.validity() - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Content && textInput == other.textInput && responseInputText == other.responseInputText && outputText == other.outputText /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(textInput, responseInputText, outputText) /* spotless:on */ - - override fun toString(): String = - when { - textInput != null -> "Content{textInput=$textInput}" - responseInputText != null -> - "Content{responseInputText=$responseInputText}" - outputText != null -> "Content{outputText=$outputText}" - _json != null -> "Content{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Content") - } - - companion object { - - /** A text input to the model. */ - @JvmStatic - fun ofTextInput(textInput: String) = Content(textInput = textInput) - - /** A text input to the model. */ - @JvmStatic - fun ofResponseInputText(responseInputText: ResponseInputText) = - Content(responseInputText = responseInputText) - - /** A text output from the model. */ - @JvmStatic - fun ofOutputText(outputText: OutputText) = Content(outputText = outputText) - } - - /** - * An interface that defines how to map each variant of [Content] to a value of - * type [T]. - */ - interface Visitor { - - /** A text input to the model. */ - fun visitTextInput(textInput: String): T - - /** A text input to the model. */ - fun visitResponseInputText(responseInputText: ResponseInputText): T - - /** A text output from the model. */ - fun visitOutputText(outputText: OutputText): T - - /** - * Maps an unknown variant of [Content] to a value of type [T]. - * - * An instance of [Content] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Content: $json") - } - } - - internal class Deserializer : BaseDeserializer(Content::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Content { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Content(responseInputText = it, _json = json) }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(outputText = it, _json = json) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - Content(textInput = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from array). - 0 -> Content(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Content::class) { - - override fun serialize( - value: Content, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.textInput != null -> generator.writeObject(value.textInput) - value.responseInputText != null -> - generator.writeObject(value.responseInputText) - value.outputText != null -> generator.writeObject(value.outputText) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Content") - } - } - } - - /** A text output from the model. */ - class OutputText - private constructor( - private val text: JsonField, - private val type: JsonValue, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("text") - @ExcludeMissing - text: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - ) : this(text, type, mutableMapOf()) - - /** - * The text output from the model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected - * type or is unexpectedly missing or null (e.g. if the server responded - * with an unexpected value). - */ - fun text(): String = text.getRequired("text") - - /** - * The type of the output text. Always `output_text`. - * - * Expected to always return the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * However, this method can be useful for debugging and logging (e.g. if the - * server responded with an unexpected value). - */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - - /** - * Returns the raw JSON value of [text]. - * - * Unlike [text], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of - * [OutputText]. - * - * The following fields are required: - * ```java - * .text() - * ``` - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [OutputText]. */ - class Builder internal constructor() { - - private var text: JsonField? = null - private var type: JsonValue = JsonValue.from("output_text") - private var additionalProperties: MutableMap = - mutableMapOf() - - @JvmSynthetic - internal fun from(outputText: OutputText) = apply { - text = outputText.text - type = outputText.type - additionalProperties = - outputText.additionalProperties.toMutableMap() - } - - /** The text output from the model. */ - fun text(text: String) = text(JsonField.of(text)) - - /** - * Sets [Builder.text] to an arbitrary JSON value. - * - * You should usually call [Builder.text] with a well-typed [String] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun text(text: JsonField) = apply { this.text = text } - - /** - * Sets the field to an arbitrary JSON value. - * - * It is usually unnecessary to call this method because the field - * defaults to the following: - * ```java - * JsonValue.from("output_text") - * ``` - * - * This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun type(type: JsonValue) = apply { this.type = type } - - fun additionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties( - additionalProperties: Map - ) = apply { this.additionalProperties.putAll(additionalProperties) } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [OutputText]. - * - * Further updates to this [Builder] will not mutate the returned - * instance. - * - * The following fields are required: - * ```java - * .text() - * ``` - * - * @throws IllegalStateException if any required field is unset. - */ - fun build(): OutputText = - OutputText( - checkRequired("text", text), - type, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): OutputText = apply { - if (validated) { - return@apply - } - - text() - _type().let { - if (it != JsonValue.from("output_text")) { - throw OpenAIInvalidDataException( - "'type' is invalid, received $it" - ) - } - } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this - * object recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (if (text.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("output_text")) 1 else 0 } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is OutputText && text == other.text && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(text, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "OutputText{text=$text, type=$type, additionalProperties=$additionalProperties}" - } - } - - /** - * The role of the message input. One of `user`, `assistant`, `system`, or - * `developer`. - */ - class Role @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val USER = of("user") - - @JvmField val ASSISTANT = of("assistant") - - @JvmField val SYSTEM = of("system") - - @JvmField val DEVELOPER = of("developer") - - @JvmStatic fun of(value: String) = Role(JsonField.of(value)) - } - - /** An enum containing [Role]'s known values. */ - enum class Known { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - } - - /** - * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Role] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - USER, - ASSISTANT, - SYSTEM, - DEVELOPER, - /** - * An enum member indicating that [Role] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - USER -> Value.USER - ASSISTANT -> Value.ASSISTANT - SYSTEM -> Value.SYSTEM - DEVELOPER -> Value.DEVELOPER - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - USER -> Known.USER - ASSISTANT -> Known.ASSISTANT - SYSTEM -> Known.SYSTEM - DEVELOPER -> Known.DEVELOPER - else -> throw OpenAIInvalidDataException("Unknown Role: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Role = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Role && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - /** The type of the message input. Always `message`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : - Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that - * doesn't match any known member, and you want to know that value. For example, - * if the SDK is on an older version than the API, then the API may respond with - * new members that the SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue - fun _value(): JsonField = value - - companion object { - - @JvmField val MESSAGE = of("message") - - @JvmStatic fun of(value: String) = Type(JsonField.of(value)) - } - - /** An enum containing [Type]'s known values. */ - enum class Known { - MESSAGE - } - - /** - * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Type] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - MESSAGE, - /** - * An enum member indicating that [Type] was instantiated with an unknown - * value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or - * if you want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - MESSAGE -> Value.MESSAGE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known - * and don't want to throw for the unknown case. - * - * @throws OpenAIInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - MESSAGE -> Known.MESSAGE - else -> throw OpenAIInvalidDataException("Unknown Type: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws OpenAIInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - OpenAIInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - fun validate(): Type = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Type && value == other.value /* spotless:on */ - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Input && content == other.content && role == other.role && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(content, role, type, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Input{content=$content, role=$role, type=$type, additionalProperties=$additionalProperties}" - } + (range.asKnown().getOrNull()?.size ?: 0) + + (if (passThreshold.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && passThreshold == other.passThreshold && range == other.range && samplingParams == other.samplingParams && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is EvalGraderScoreModel && input == other.input && model == other.model && name == other.name && type == other.type && range == other.range && samplingParams == other.samplingParams && passThreshold == other.passThreshold && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(input, model, name, type, passThreshold, range, samplingParams, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(input, model, name, type, range, samplingParams, passThreshold, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "ScoreModel{input=$input, model=$model, name=$name, type=$type, passThreshold=$passThreshold, range=$range, samplingParams=$samplingParams, additionalProperties=$additionalProperties}" + "EvalGraderScoreModel{input=$input, model=$model, name=$name, type=$type, range=$range, samplingParams=$samplingParams, passThreshold=$passThreshold, additionalProperties=$additionalProperties}" } } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCancelParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCancelParams.kt index 63c37ab08..05903cbdf 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCancelParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCancelParams.kt @@ -10,12 +10,13 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Cancel an ongoing evaluation run. */ class RunCancelParams private constructor( private val evalId: String, - private val runId: String, + private val runId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -23,7 +24,7 @@ private constructor( fun evalId(): String = evalId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -41,7 +42,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -67,7 +67,10 @@ private constructor( fun evalId(evalId: String) = apply { this.evalId = evalId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -197,7 +200,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -205,7 +207,7 @@ private constructor( fun build(): RunCancelParams = RunCancelParams( checkRequired("evalId", evalId), - checkRequired("runId", runId), + runId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -218,7 +220,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> evalId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCreateParams.kt index 952e12bab..a50d3f6dd 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunCreateParams.kt @@ -39,13 +39,13 @@ import kotlin.jvm.optionals.getOrNull /** Create a new evaluation run. This is the endpoint that will kick off grading. */ class RunCreateParams private constructor( - private val evalId: String, + private val evalId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun evalId(): String = evalId + fun evalId(): Optional = Optional.ofNullable(evalId) /** * Details about the run's data source. @@ -112,7 +112,6 @@ private constructor( * * The following fields are required: * ```java - * .evalId() * .dataSource() * ``` */ @@ -135,7 +134,10 @@ private constructor( additionalQueryParams = runCreateParams.additionalQueryParams.toBuilder() } - fun evalId(evalId: String) = apply { this.evalId = evalId } + fun evalId(evalId: String?) = apply { this.evalId = evalId } + + /** Alias for calling [Builder.evalId] with `evalId.orElse(null)`. */ + fun evalId(evalId: Optional) = evalId(evalId.getOrNull()) /** * Sets the entire request body. @@ -342,7 +344,6 @@ private constructor( * * The following fields are required: * ```java - * .evalId() * .dataSource() * ``` * @@ -350,7 +351,7 @@ private constructor( */ fun build(): RunCreateParams = RunCreateParams( - checkRequired("evalId", evalId), + evalId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -361,7 +362,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> evalId + 0 -> evalId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunDeleteParams.kt index 2214b0d23..784ca9c03 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunDeleteParams.kt @@ -10,12 +10,13 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Delete an eval run. */ class RunDeleteParams private constructor( private val evalId: String, - private val runId: String, + private val runId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -23,7 +24,7 @@ private constructor( fun evalId(): String = evalId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -41,7 +42,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -67,7 +67,10 @@ private constructor( fun evalId(evalId: String) = apply { this.evalId = evalId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -197,7 +200,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -205,7 +207,7 @@ private constructor( fun build(): RunDeleteParams = RunDeleteParams( checkRequired("evalId", evalId), - checkRequired("runId", runId), + runId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -218,7 +220,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> evalId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPage.kt index ca22d061c..4e9fc0d74 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.evals.runs +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.evals.RunService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [RunService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: RunService, private val params: RunListParams, private val response: RunListPageResponse, -) { +) : Page { /** * Delegates to [RunListPageResponse], but gracefully handles missing data. @@ -33,19 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): RunListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): RunListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): RunListParams = params @@ -114,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: RunListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPageAsync.kt index f159f3923..a914663d6 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.evals.runs +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.evals.RunServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [RunServiceAsync.list] */ class RunListPageAsync private constructor( private val service: RunServiceAsync, + private val streamHandlerExecutor: Executor, private val params: RunListParams, private val response: RunListPageResponse, -) { +) : PageAsync { /** * Delegates to [RunListPageResponse], but gracefully handles missing data. @@ -34,22 +36,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): RunListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): RunListParams = params @@ -67,6 +64,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +76,24 @@ private constructor( class Builder internal constructor() { private var service: RunServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: RunListParams? = null private var response: RunListPageResponse? = null @JvmSynthetic internal fun from(runListPageAsync: RunListPageAsync) = apply { service = runListPageAsync.service + streamHandlerExecutor = runListPageAsync.streamHandlerExecutor params = runListPageAsync.params response = runListPageAsync.response } fun service(service: RunServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: RunListParams) = apply { this.params = params } @@ -104,6 +108,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +118,22 @@ private constructor( fun build(): RunListPageAsync = RunListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: RunListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (RunListResponse) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is RunListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is RunListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "RunListPageAsync{service=$service, params=$params, response=$response}" + "RunListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListParams.kt index b825f64b6..56035b50d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunListParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.errors.OpenAIInvalidDataException @@ -17,7 +16,7 @@ import kotlin.jvm.optionals.getOrNull /** Get a list of runs for an evaluation. */ class RunListParams private constructor( - private val evalId: String, + private val evalId: String?, private val after: String?, private val limit: Long?, private val order: Order?, @@ -26,7 +25,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun evalId(): String = evalId + fun evalId(): Optional = Optional.ofNullable(evalId) /** Identifier for the last run from the previous pagination request. */ fun after(): Optional = Optional.ofNullable(after) @@ -53,14 +52,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [RunListParams]. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - */ + @JvmStatic fun none(): RunListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [RunListParams]. */ @JvmStatic fun builder() = Builder() } @@ -86,7 +80,10 @@ private constructor( additionalQueryParams = runListParams.additionalQueryParams.toBuilder() } - fun evalId(evalId: String) = apply { this.evalId = evalId } + fun evalId(evalId: String?) = apply { this.evalId = evalId } + + /** Alias for calling [Builder.evalId] with `evalId.orElse(null)`. */ + fun evalId(evalId: Optional) = evalId(evalId.getOrNull()) /** Identifier for the last run from the previous pagination request. */ fun after(after: String?) = apply { this.after = after } @@ -227,17 +224,10 @@ private constructor( * Returns an immutable instance of [RunListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .evalId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): RunListParams = RunListParams( - checkRequired("evalId", evalId), + evalId, after, limit, order, @@ -249,7 +239,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> evalId + 0 -> evalId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunRetrieveParams.kt index b5cfc5002..26e388e7c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/RunRetrieveParams.kt @@ -7,19 +7,21 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Get an evaluation run by ID. */ class RunRetrieveParams private constructor( private val evalId: String, - private val runId: String, + private val runId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun evalId(): String = evalId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) fun _additionalHeaders(): Headers = additionalHeaders @@ -35,7 +37,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -59,7 +60,10 @@ private constructor( fun evalId(evalId: String) = apply { this.evalId = evalId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -167,7 +171,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -175,7 +178,7 @@ private constructor( fun build(): RunRetrieveParams = RunRetrieveParams( checkRequired("evalId", evalId), - checkRequired("runId", runId), + runId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -184,7 +187,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> evalId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPage.kt index e24395a2d..b75e0d39b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.evals.runs.outputitems +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.evals.runs.OutputItemService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [OutputItemService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: OutputItemService, private val params: OutputItemListParams, private val response: OutputItemListPageResponse, -) { +) : Page { /** * Delegates to [OutputItemListPageResponse], but gracefully handles missing data. @@ -33,19 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): OutputItemListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): OutputItemListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): OutputItemListParams = params @@ -114,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: OutputItemListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPageAsync.kt index 9e5c96350..c12bf482b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.evals.runs.outputitems +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.evals.runs.OutputItemServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [OutputItemServiceAsync.list] */ class OutputItemListPageAsync private constructor( private val service: OutputItemServiceAsync, + private val streamHandlerExecutor: Executor, private val params: OutputItemListParams, private val response: OutputItemListPageResponse, -) { +) : PageAsync { /** * Delegates to [OutputItemListPageResponse], but gracefully handles missing data. @@ -34,22 +36,18 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): OutputItemListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): OutputItemListParams = params @@ -67,6 +65,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +77,24 @@ private constructor( class Builder internal constructor() { private var service: OutputItemServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: OutputItemListParams? = null private var response: OutputItemListPageResponse? = null @JvmSynthetic internal fun from(outputItemListPageAsync: OutputItemListPageAsync) = apply { service = outputItemListPageAsync.service + streamHandlerExecutor = outputItemListPageAsync.streamHandlerExecutor params = outputItemListPageAsync.params response = outputItemListPageAsync.response } fun service(service: OutputItemServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: OutputItemListParams) = apply { this.params = params } @@ -104,6 +109,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +119,22 @@ private constructor( fun build(): OutputItemListPageAsync = OutputItemListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: OutputItemListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (OutputItemListResponse) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is OutputItemListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is OutputItemListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "OutputItemListPageAsync{service=$service, params=$params, response=$response}" + "OutputItemListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListParams.kt index 4c6c896be..d7b882106 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemListParams.kt @@ -18,7 +18,7 @@ import kotlin.jvm.optionals.getOrNull class OutputItemListParams private constructor( private val evalId: String, - private val runId: String, + private val runId: String?, private val after: String?, private val limit: Long?, private val order: Order?, @@ -29,7 +29,7 @@ private constructor( fun evalId(): String = evalId - fun runId(): String = runId + fun runId(): Optional = Optional.ofNullable(runId) /** Identifier for the last output item from the previous pagination request. */ fun after(): Optional = Optional.ofNullable(after) @@ -63,7 +63,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` */ @JvmStatic fun builder() = Builder() @@ -95,7 +94,10 @@ private constructor( fun evalId(evalId: String) = apply { this.evalId = evalId } - fun runId(runId: String) = apply { this.runId = runId } + fun runId(runId: String?) = apply { this.runId = runId } + + /** Alias for calling [Builder.runId] with `runId.orElse(null)`. */ + fun runId(runId: Optional) = runId(runId.getOrNull()) /** Identifier for the last output item from the previous pagination request. */ fun after(after: String?) = apply { this.after = after } @@ -240,7 +242,6 @@ private constructor( * The following fields are required: * ```java * .evalId() - * .runId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -248,7 +249,7 @@ private constructor( fun build(): OutputItemListParams = OutputItemListParams( checkRequired("evalId", evalId), - checkRequired("runId", runId), + runId, after, limit, order, @@ -261,7 +262,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> evalId - 1 -> runId + 1 -> runId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemRetrieveParams.kt index 3d1a3ce32..361599f5b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/evals/runs/outputitems/OutputItemRetrieveParams.kt @@ -7,13 +7,15 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Get an evaluation run output item by ID. */ class OutputItemRetrieveParams private constructor( private val evalId: String, private val runId: String, - private val outputItemId: String, + private val outputItemId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { @@ -22,7 +24,7 @@ private constructor( fun runId(): String = runId - fun outputItemId(): String = outputItemId + fun outputItemId(): Optional = Optional.ofNullable(outputItemId) fun _additionalHeaders(): Headers = additionalHeaders @@ -39,7 +41,6 @@ private constructor( * ```java * .evalId() * .runId() - * .outputItemId() * ``` */ @JvmStatic fun builder() = Builder() @@ -67,7 +68,10 @@ private constructor( fun runId(runId: String) = apply { this.runId = runId } - fun outputItemId(outputItemId: String) = apply { this.outputItemId = outputItemId } + fun outputItemId(outputItemId: String?) = apply { this.outputItemId = outputItemId } + + /** Alias for calling [Builder.outputItemId] with `outputItemId.orElse(null)`. */ + fun outputItemId(outputItemId: Optional) = outputItemId(outputItemId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -176,7 +180,6 @@ private constructor( * ```java * .evalId() * .runId() - * .outputItemId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -185,7 +188,7 @@ private constructor( OutputItemRetrieveParams( checkRequired("evalId", evalId), checkRequired("runId", runId), - checkRequired("outputItemId", outputItemId), + outputItemId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -195,7 +198,7 @@ private constructor( when (index) { 0 -> evalId 1 -> runId - 2 -> outputItemId + 2 -> outputItemId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/files/FileContentParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/files/FileContentParams.kt index 0a4ea8abb..5035b1689 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/files/FileContentParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/files/FileContentParams.kt @@ -3,20 +3,21 @@ package com.openai.models.files import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Returns the contents of the specified file. */ class FileContentParams private constructor( - private val fileId: String, + private val fileId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,14 +27,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [FileContentParams]. - * - * The following fields are required: - * ```java - * .fileId() - * ``` - */ + @JvmStatic fun none(): FileContentParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FileContentParams]. */ @JvmStatic fun builder() = Builder() } @@ -51,7 +47,10 @@ private constructor( additionalQueryParams = fileContentParams.additionalQueryParams.toBuilder() } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,25 +154,14 @@ private constructor( * Returns an immutable instance of [FileContentParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fileId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): FileContentParams = - FileContentParams( - checkRequired("fileId", fileId), - additionalHeaders.build(), - additionalQueryParams.build(), - ) + FileContentParams(fileId, additionalHeaders.build(), additionalQueryParams.build()) } fun _pathParam(index: Int): String = when (index) { - 0 -> fileId + 0 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/files/FileDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/files/FileDeleteParams.kt index 2bc93b6a9..dca35f8a6 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/files/FileDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/files/FileDeleteParams.kt @@ -4,23 +4,23 @@ package com.openai.models.files import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Delete a file. */ class FileDeleteParams private constructor( - private val fileId: String, + private val fileId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [FileDeleteParams]. - * - * The following fields are required: - * ```java - * .fileId() - * ``` - */ + @JvmStatic fun none(): FileDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FileDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,7 +54,10 @@ private constructor( additionalBodyProperties = fileDeleteParams.additionalBodyProperties.toMutableMap() } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -185,17 +183,10 @@ private constructor( * Returns an immutable instance of [FileDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fileId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): FileDeleteParams = FileDeleteParams( - checkRequired("fileId", fileId), + fileId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -207,7 +198,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fileId + 0 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPage.kt index 2aa16da39..9310e1348 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.files +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.FileService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [FileService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: FileService, private val params: FileListParams, private val response: FileListPageResponse, -) { +) : Page { /** * Delegates to [FileListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): FileListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): FileListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): FileListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: FileListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPageAsync.kt index ec8e2d6c5..7f775f0c3 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/files/FileListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.files +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.FileServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [FileServiceAsync.list] */ class FileListPageAsync private constructor( private val service: FileServiceAsync, + private val streamHandlerExecutor: Executor, private val params: FileListParams, private val response: FileListPageResponse, -) { +) : PageAsync { /** * Delegates to [FileListPageResponse], but gracefully handles missing data. @@ -33,22 +35,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): FileListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): FileListParams = params @@ -66,6 +62,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +74,24 @@ private constructor( class Builder internal constructor() { private var service: FileServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: FileListParams? = null private var response: FileListPageResponse? = null @JvmSynthetic internal fun from(fileListPageAsync: FileListPageAsync) = apply { service = fileListPageAsync.service + streamHandlerExecutor = fileListPageAsync.streamHandlerExecutor params = fileListPageAsync.params response = fileListPageAsync.response } fun service(service: FileServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: FileListParams) = apply { this.params = params } @@ -103,6 +106,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +116,22 @@ private constructor( fun build(): FileListPageAsync = FileListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: FileListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (FileObject) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is FileListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is FileListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "FileListPageAsync{service=$service, params=$params, response=$response}" + "FileListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/files/FileRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/files/FileRetrieveParams.kt index 379eb2f10..cb00e7084 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/files/FileRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/files/FileRetrieveParams.kt @@ -3,20 +3,21 @@ package com.openai.models.files import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Returns information about a specific file. */ class FileRetrieveParams private constructor( - private val fileId: String, + private val fileId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,14 +27,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [FileRetrieveParams]. - * - * The following fields are required: - * ```java - * .fileId() - * ``` - */ + @JvmStatic fun none(): FileRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FileRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -51,7 +47,10 @@ private constructor( additionalQueryParams = fileRetrieveParams.additionalQueryParams.toBuilder() } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,25 +154,14 @@ private constructor( * Returns an immutable instance of [FileRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fileId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): FileRetrieveParams = - FileRetrieveParams( - checkRequired("fileId", fileId), - additionalHeaders.build(), - additionalQueryParams.build(), - ) + FileRetrieveParams(fileId, additionalHeaders.build(), additionalQueryParams.build()) } fun _pathParam(index: Int): String = when (index) { - 0 -> fileId + 0 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunParams.kt new file mode 100644 index 000000000..cd49645da --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunParams.kt @@ -0,0 +1,1145 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.Params +import com.openai.core.allMaxBy +import com.openai.core.checkRequired +import com.openai.core.getOrThrow +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.graders.gradermodels.MultiGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Run a grader. */ +class GraderRunParams +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * The grader used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun grader(): Grader = body.grader() + + /** + * The model sample to be evaluated. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun modelSample(): String = body.modelSample() + + /** + * The reference answer for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun referenceAnswer(): ReferenceAnswer = body.referenceAnswer() + + /** + * Returns the raw JSON value of [grader]. + * + * Unlike [grader], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _grader(): JsonField = body._grader() + + /** + * Returns the raw JSON value of [modelSample]. + * + * Unlike [modelSample], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _modelSample(): JsonField = body._modelSample() + + /** + * Returns the raw JSON value of [referenceAnswer]. + * + * Unlike [referenceAnswer], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _referenceAnswer(): JsonField = body._referenceAnswer() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [GraderRunParams]. + * + * The following fields are required: + * ```java + * .grader() + * .modelSample() + * .referenceAnswer() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GraderRunParams]. */ + class Builder internal constructor() { + + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(graderRunParams: GraderRunParams) = apply { + body = graderRunParams.body.toBuilder() + additionalHeaders = graderRunParams.additionalHeaders.toBuilder() + additionalQueryParams = graderRunParams.additionalQueryParams.toBuilder() + } + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [grader] + * - [modelSample] + * - [referenceAnswer] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** The grader used for the fine-tuning job. */ + fun grader(grader: Grader) = apply { body.grader(grader) } + + /** + * Sets [Builder.grader] to an arbitrary JSON value. + * + * You should usually call [Builder.grader] with a well-typed [Grader] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun grader(grader: JsonField) = apply { body.grader(grader) } + + /** Alias for calling [grader] with `Grader.ofStringCheck(stringCheck)`. */ + fun grader(stringCheck: StringCheckGrader) = apply { body.grader(stringCheck) } + + /** Alias for calling [grader] with `Grader.ofTextSimilarity(textSimilarity)`. */ + fun grader(textSimilarity: TextSimilarityGrader) = apply { body.grader(textSimilarity) } + + /** Alias for calling [grader] with `Grader.ofPython(python)`. */ + fun grader(python: PythonGrader) = apply { body.grader(python) } + + /** Alias for calling [grader] with `Grader.ofScoreModel(scoreModel)`. */ + fun grader(scoreModel: ScoreModelGrader) = apply { body.grader(scoreModel) } + + /** Alias for calling [grader] with `Grader.ofMulti(multi)`. */ + fun grader(multi: MultiGrader) = apply { body.grader(multi) } + + /** The model sample to be evaluated. */ + fun modelSample(modelSample: String) = apply { body.modelSample(modelSample) } + + /** + * Sets [Builder.modelSample] to an arbitrary JSON value. + * + * You should usually call [Builder.modelSample] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun modelSample(modelSample: JsonField) = apply { body.modelSample(modelSample) } + + /** The reference answer for the evaluation. */ + fun referenceAnswer(referenceAnswer: ReferenceAnswer) = apply { + body.referenceAnswer(referenceAnswer) + } + + /** + * Sets [Builder.referenceAnswer] to an arbitrary JSON value. + * + * You should usually call [Builder.referenceAnswer] with a well-typed [ReferenceAnswer] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun referenceAnswer(referenceAnswer: JsonField) = apply { + body.referenceAnswer(referenceAnswer) + } + + /** Alias for calling [referenceAnswer] with `ReferenceAnswer.ofString(string)`. */ + fun referenceAnswer(string: String) = apply { body.referenceAnswer(string) } + + /** Alias for calling [referenceAnswer] with `ReferenceAnswer.ofJsonValue(jsonValue)`. */ + fun referenceAnswer(jsonValue: JsonValue) = apply { body.referenceAnswer(jsonValue) } + + /** Alias for calling [referenceAnswer] with `ReferenceAnswer.ofJsonValues(jsonValues)`. */ + fun referenceAnswerOfJsonValues(jsonValues: List) = apply { + body.referenceAnswerOfJsonValues(jsonValues) + } + + /** Alias for calling [referenceAnswer] with `ReferenceAnswer.ofNumber(number)`. */ + fun referenceAnswer(number: Double) = apply { body.referenceAnswer(number) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [GraderRunParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .grader() + * .modelSample() + * .referenceAnswer() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GraderRunParams = + GraderRunParams(body.build(), additionalHeaders.build(), additionalQueryParams.build()) + } + + fun _body(): Body = body + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + private constructor( + private val grader: JsonField, + private val modelSample: JsonField, + private val referenceAnswer: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("grader") @ExcludeMissing grader: JsonField = JsonMissing.of(), + @JsonProperty("model_sample") + @ExcludeMissing + modelSample: JsonField = JsonMissing.of(), + @JsonProperty("reference_answer") + @ExcludeMissing + referenceAnswer: JsonField = JsonMissing.of(), + ) : this(grader, modelSample, referenceAnswer, mutableMapOf()) + + /** + * The grader used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun grader(): Grader = grader.getRequired("grader") + + /** + * The model sample to be evaluated. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun modelSample(): String = modelSample.getRequired("model_sample") + + /** + * The reference answer for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun referenceAnswer(): ReferenceAnswer = referenceAnswer.getRequired("reference_answer") + + /** + * Returns the raw JSON value of [grader]. + * + * Unlike [grader], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("grader") @ExcludeMissing fun _grader(): JsonField = grader + + /** + * Returns the raw JSON value of [modelSample]. + * + * Unlike [modelSample], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model_sample") + @ExcludeMissing + fun _modelSample(): JsonField = modelSample + + /** + * Returns the raw JSON value of [referenceAnswer]. + * + * Unlike [referenceAnswer], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("reference_answer") + @ExcludeMissing + fun _referenceAnswer(): JsonField = referenceAnswer + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .grader() + * .modelSample() + * .referenceAnswer() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var grader: JsonField? = null + private var modelSample: JsonField? = null + private var referenceAnswer: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + grader = body.grader + modelSample = body.modelSample + referenceAnswer = body.referenceAnswer + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The grader used for the fine-tuning job. */ + fun grader(grader: Grader) = grader(JsonField.of(grader)) + + /** + * Sets [Builder.grader] to an arbitrary JSON value. + * + * You should usually call [Builder.grader] with a well-typed [Grader] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun grader(grader: JsonField) = apply { this.grader = grader } + + /** Alias for calling [grader] with `Grader.ofStringCheck(stringCheck)`. */ + fun grader(stringCheck: StringCheckGrader) = grader(Grader.ofStringCheck(stringCheck)) + + /** Alias for calling [grader] with `Grader.ofTextSimilarity(textSimilarity)`. */ + fun grader(textSimilarity: TextSimilarityGrader) = + grader(Grader.ofTextSimilarity(textSimilarity)) + + /** Alias for calling [grader] with `Grader.ofPython(python)`. */ + fun grader(python: PythonGrader) = grader(Grader.ofPython(python)) + + /** Alias for calling [grader] with `Grader.ofScoreModel(scoreModel)`. */ + fun grader(scoreModel: ScoreModelGrader) = grader(Grader.ofScoreModel(scoreModel)) + + /** Alias for calling [grader] with `Grader.ofMulti(multi)`. */ + fun grader(multi: MultiGrader) = grader(Grader.ofMulti(multi)) + + /** The model sample to be evaluated. */ + fun modelSample(modelSample: String) = modelSample(JsonField.of(modelSample)) + + /** + * Sets [Builder.modelSample] to an arbitrary JSON value. + * + * You should usually call [Builder.modelSample] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun modelSample(modelSample: JsonField) = apply { + this.modelSample = modelSample + } + + /** The reference answer for the evaluation. */ + fun referenceAnswer(referenceAnswer: ReferenceAnswer) = + referenceAnswer(JsonField.of(referenceAnswer)) + + /** + * Sets [Builder.referenceAnswer] to an arbitrary JSON value. + * + * You should usually call [Builder.referenceAnswer] with a well-typed [ReferenceAnswer] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun referenceAnswer(referenceAnswer: JsonField) = apply { + this.referenceAnswer = referenceAnswer + } + + /** Alias for calling [referenceAnswer] with `ReferenceAnswer.ofString(string)`. */ + fun referenceAnswer(string: String) = referenceAnswer(ReferenceAnswer.ofString(string)) + + /** + * Alias for calling [referenceAnswer] with `ReferenceAnswer.ofJsonValue(jsonValue)`. + */ + fun referenceAnswer(jsonValue: JsonValue) = + referenceAnswer(ReferenceAnswer.ofJsonValue(jsonValue)) + + /** + * Alias for calling [referenceAnswer] with `ReferenceAnswer.ofJsonValues(jsonValues)`. + */ + fun referenceAnswerOfJsonValues(jsonValues: List) = + referenceAnswer(ReferenceAnswer.ofJsonValues(jsonValues)) + + /** Alias for calling [referenceAnswer] with `ReferenceAnswer.ofNumber(number)`. */ + fun referenceAnswer(number: Double) = referenceAnswer(ReferenceAnswer.ofNumber(number)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .grader() + * .modelSample() + * .referenceAnswer() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body( + checkRequired("grader", grader), + checkRequired("modelSample", modelSample), + checkRequired("referenceAnswer", referenceAnswer), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + grader().validate() + modelSample() + referenceAnswer().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (grader.asKnown().getOrNull()?.validity() ?: 0) + + (if (modelSample.asKnown().isPresent) 1 else 0) + + (referenceAnswer.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Body && grader == other.grader && modelSample == other.modelSample && referenceAnswer == other.referenceAnswer && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(grader, modelSample, referenceAnswer, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Body{grader=$grader, modelSample=$modelSample, referenceAnswer=$referenceAnswer, additionalProperties=$additionalProperties}" + } + + /** The grader used for the fine-tuning job. */ + @JsonDeserialize(using = Grader.Deserializer::class) + @JsonSerialize(using = Grader.Serializer::class) + class Grader + private constructor( + private val stringCheck: StringCheckGrader? = null, + private val textSimilarity: TextSimilarityGrader? = null, + private val python: PythonGrader? = null, + private val scoreModel: ScoreModelGrader? = null, + private val multi: MultiGrader? = null, + private val _json: JsonValue? = null, + ) { + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun textSimilarity(): Optional = Optional.ofNullable(textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + fun python(): Optional = Optional.ofNullable(python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun multi(): Optional = Optional.ofNullable(multi) + + fun isStringCheck(): Boolean = stringCheck != null + + fun isTextSimilarity(): Boolean = textSimilarity != null + + fun isPython(): Boolean = python != null + + fun isScoreModel(): Boolean = scoreModel != null + + fun isMulti(): Boolean = multi != null + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun asStringCheck(): StringCheckGrader = stringCheck.getOrThrow("stringCheck") + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun asTextSimilarity(): TextSimilarityGrader = textSimilarity.getOrThrow("textSimilarity") + + /** A PythonGrader object that runs a python script on the input. */ + fun asPython(): PythonGrader = python.getOrThrow("python") + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun asScoreModel(): ScoreModelGrader = scoreModel.getOrThrow("scoreModel") + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun asMulti(): MultiGrader = multi.getOrThrow("multi") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + stringCheck != null -> visitor.visitStringCheck(stringCheck) + textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) + python != null -> visitor.visitPython(python) + scoreModel != null -> visitor.visitScoreModel(scoreModel) + multi != null -> visitor.visitMulti(multi) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Grader = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) { + stringCheck.validate() + } + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) { + textSimilarity.validate() + } + + override fun visitPython(python: PythonGrader) { + python.validate() + } + + override fun visitScoreModel(scoreModel: ScoreModelGrader) { + scoreModel.validate() + } + + override fun visitMulti(multi: MultiGrader) { + multi.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) = + stringCheck.validity() + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) = + textSimilarity.validity() + + override fun visitPython(python: PythonGrader) = python.validity() + + override fun visitScoreModel(scoreModel: ScoreModelGrader) = + scoreModel.validity() + + override fun visitMulti(multi: MultiGrader) = multi.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Grader && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel && multi == other.multi /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(stringCheck, textSimilarity, python, scoreModel, multi) /* spotless:on */ + + override fun toString(): String = + when { + stringCheck != null -> "Grader{stringCheck=$stringCheck}" + textSimilarity != null -> "Grader{textSimilarity=$textSimilarity}" + python != null -> "Grader{python=$python}" + scoreModel != null -> "Grader{scoreModel=$scoreModel}" + multi != null -> "Grader{multi=$multi}" + _json != null -> "Grader{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Grader") + } + + companion object { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + @JvmStatic + fun ofStringCheck(stringCheck: StringCheckGrader) = Grader(stringCheck = stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + @JvmStatic + fun ofTextSimilarity(textSimilarity: TextSimilarityGrader) = + Grader(textSimilarity = textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + @JvmStatic fun ofPython(python: PythonGrader) = Grader(python = python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + @JvmStatic + fun ofScoreModel(scoreModel: ScoreModelGrader) = Grader(scoreModel = scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + @JvmStatic fun ofMulti(multi: MultiGrader) = Grader(multi = multi) + } + + /** An interface that defines how to map each variant of [Grader] to a value of type [T]. */ + interface Visitor { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + fun visitStringCheck(stringCheck: StringCheckGrader): T + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun visitTextSimilarity(textSimilarity: TextSimilarityGrader): T + + /** A PythonGrader object that runs a python script on the input. */ + fun visitPython(python: PythonGrader): T + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun visitScoreModel(scoreModel: ScoreModelGrader): T + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + fun visitMulti(multi: MultiGrader): T + + /** + * Maps an unknown variant of [Grader] to a value of type [T]. + * + * An instance of [Grader] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Grader: $json") + } + } + + internal class Deserializer : BaseDeserializer(Grader::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Grader { + val json = JsonValue.fromJsonNode(node) + val type = json.asObject().getOrNull()?.get("type")?.asString()?.getOrNull() + + when (type) { + "string_check" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Grader(stringCheck = it, _json = json) + } ?: Grader(_json = json) + } + "text_similarity" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Grader(textSimilarity = it, _json = json) + } ?: Grader(_json = json) + } + "python" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Grader(python = it, _json = json) + } ?: Grader(_json = json) + } + "score_model" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Grader(scoreModel = it, _json = json) + } ?: Grader(_json = json) + } + "multi" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + Grader(multi = it, _json = json) + } ?: Grader(_json = json) + } + } + + return Grader(_json = json) + } + } + + internal class Serializer : BaseSerializer(Grader::class) { + + override fun serialize( + value: Grader, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.stringCheck != null -> generator.writeObject(value.stringCheck) + value.textSimilarity != null -> generator.writeObject(value.textSimilarity) + value.python != null -> generator.writeObject(value.python) + value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.multi != null -> generator.writeObject(value.multi) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Grader") + } + } + } + } + + /** The reference answer for the evaluation. */ + @JsonDeserialize(using = ReferenceAnswer.Deserializer::class) + @JsonSerialize(using = ReferenceAnswer.Serializer::class) + class ReferenceAnswer + private constructor( + private val string: String? = null, + private val jsonValue: JsonValue? = null, + private val jsonValues: List? = null, + private val number: Double? = null, + private val _json: JsonValue? = null, + ) { + + fun string(): Optional = Optional.ofNullable(string) + + fun jsonValue(): Optional = Optional.ofNullable(jsonValue) + + fun jsonValues(): Optional> = Optional.ofNullable(jsonValues) + + fun number(): Optional = Optional.ofNullable(number) + + fun isString(): Boolean = string != null + + fun isJsonValue(): Boolean = jsonValue != null + + fun isJsonValues(): Boolean = jsonValues != null + + fun isNumber(): Boolean = number != null + + fun asString(): String = string.getOrThrow("string") + + fun asJsonValue(): JsonValue = jsonValue.getOrThrow("jsonValue") + + fun asJsonValues(): List = jsonValues.getOrThrow("jsonValues") + + fun asNumber(): Double = number.getOrThrow("number") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + string != null -> visitor.visitString(string) + jsonValue != null -> visitor.visitJsonValue(jsonValue) + jsonValues != null -> visitor.visitJsonValues(jsonValues) + number != null -> visitor.visitNumber(number) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ReferenceAnswer = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitString(string: String) {} + + override fun visitJsonValue(jsonValue: JsonValue) {} + + override fun visitJsonValues(jsonValues: List) {} + + override fun visitNumber(number: Double) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitString(string: String) = 1 + + override fun visitJsonValue(jsonValue: JsonValue) = 1 + + override fun visitJsonValues(jsonValues: List) = jsonValues.size + + override fun visitNumber(number: Double) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ReferenceAnswer && string == other.string && jsonValue == other.jsonValue && jsonValues == other.jsonValues && number == other.number /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(string, jsonValue, jsonValues, number) /* spotless:on */ + + override fun toString(): String = + when { + string != null -> "ReferenceAnswer{string=$string}" + jsonValue != null -> "ReferenceAnswer{jsonValue=$jsonValue}" + jsonValues != null -> "ReferenceAnswer{jsonValues=$jsonValues}" + number != null -> "ReferenceAnswer{number=$number}" + _json != null -> "ReferenceAnswer{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ReferenceAnswer") + } + + companion object { + + @JvmStatic fun ofString(string: String) = ReferenceAnswer(string = string) + + @JvmStatic + fun ofJsonValue(jsonValue: JsonValue) = ReferenceAnswer(jsonValue = jsonValue) + + @JvmStatic + fun ofJsonValues(jsonValues: List) = ReferenceAnswer(jsonValues = jsonValues) + + @JvmStatic fun ofNumber(number: Double) = ReferenceAnswer(number = number) + } + + /** + * An interface that defines how to map each variant of [ReferenceAnswer] to a value of type + * [T]. + */ + interface Visitor { + + fun visitString(string: String): T + + fun visitJsonValue(jsonValue: JsonValue): T + + fun visitJsonValues(jsonValues: List): T + + fun visitNumber(number: Double): T + + /** + * Maps an unknown variant of [ReferenceAnswer] to a value of type [T]. + * + * An instance of [ReferenceAnswer] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown ReferenceAnswer: $json") + } + } + + internal class Deserializer : BaseDeserializer(ReferenceAnswer::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ReferenceAnswer { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + ReferenceAnswer(string = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef>())?.let { + ReferenceAnswer(jsonValues = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ReferenceAnswer(number = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + ReferenceAnswer(jsonValue = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants. + 0 -> ReferenceAnswer(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(ReferenceAnswer::class) { + + override fun serialize( + value: ReferenceAnswer, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.string != null -> generator.writeObject(value.string) + value.jsonValue != null -> generator.writeObject(value.jsonValue) + value.jsonValues != null -> generator.writeObject(value.jsonValues) + value.number != null -> generator.writeObject(value.number) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ReferenceAnswer") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GraderRunParams && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(body, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "GraderRunParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunResponse.kt new file mode 100644 index 000000000..6523c6c5b --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunResponse.kt @@ -0,0 +1,1772 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.checkRequired +import com.openai.core.toImmutable +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class GraderRunResponse +private constructor( + private val metadata: JsonField, + private val modelGraderTokenUsagePerModel: JsonField, + private val reward: JsonField, + private val subRewards: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("metadata") @ExcludeMissing metadata: JsonField = JsonMissing.of(), + @JsonProperty("model_grader_token_usage_per_model") + @ExcludeMissing + modelGraderTokenUsagePerModel: JsonField = JsonMissing.of(), + @JsonProperty("reward") @ExcludeMissing reward: JsonField = JsonMissing.of(), + @JsonProperty("sub_rewards") + @ExcludeMissing + subRewards: JsonField = JsonMissing.of(), + ) : this(metadata, modelGraderTokenUsagePerModel, reward, subRewards, mutableMapOf()) + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun metadata(): Metadata = metadata.getRequired("metadata") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun modelGraderTokenUsagePerModel(): ModelGraderTokenUsagePerModel = + modelGraderTokenUsagePerModel.getRequired("model_grader_token_usage_per_model") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun reward(): Double = reward.getRequired("reward") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun subRewards(): SubRewards = subRewards.getRequired("sub_rewards") + + /** + * Returns the raw JSON value of [metadata]. + * + * Unlike [metadata], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("metadata") @ExcludeMissing fun _metadata(): JsonField = metadata + + /** + * Returns the raw JSON value of [modelGraderTokenUsagePerModel]. + * + * Unlike [modelGraderTokenUsagePerModel], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("model_grader_token_usage_per_model") + @ExcludeMissing + fun _modelGraderTokenUsagePerModel(): JsonField = + modelGraderTokenUsagePerModel + + /** + * Returns the raw JSON value of [reward]. + * + * Unlike [reward], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reward") @ExcludeMissing fun _reward(): JsonField = reward + + /** + * Returns the raw JSON value of [subRewards]. + * + * Unlike [subRewards], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sub_rewards") + @ExcludeMissing + fun _subRewards(): JsonField = subRewards + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [GraderRunResponse]. + * + * The following fields are required: + * ```java + * .metadata() + * .modelGraderTokenUsagePerModel() + * .reward() + * .subRewards() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GraderRunResponse]. */ + class Builder internal constructor() { + + private var metadata: JsonField? = null + private var modelGraderTokenUsagePerModel: JsonField? = null + private var reward: JsonField? = null + private var subRewards: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(graderRunResponse: GraderRunResponse) = apply { + metadata = graderRunResponse.metadata + modelGraderTokenUsagePerModel = graderRunResponse.modelGraderTokenUsagePerModel + reward = graderRunResponse.reward + subRewards = graderRunResponse.subRewards + additionalProperties = graderRunResponse.additionalProperties.toMutableMap() + } + + fun metadata(metadata: Metadata) = metadata(JsonField.of(metadata)) + + /** + * Sets [Builder.metadata] to an arbitrary JSON value. + * + * You should usually call [Builder.metadata] with a well-typed [Metadata] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun metadata(metadata: JsonField) = apply { this.metadata = metadata } + + fun modelGraderTokenUsagePerModel( + modelGraderTokenUsagePerModel: ModelGraderTokenUsagePerModel + ) = modelGraderTokenUsagePerModel(JsonField.of(modelGraderTokenUsagePerModel)) + + /** + * Sets [Builder.modelGraderTokenUsagePerModel] to an arbitrary JSON value. + * + * You should usually call [Builder.modelGraderTokenUsagePerModel] with a well-typed + * [ModelGraderTokenUsagePerModel] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun modelGraderTokenUsagePerModel( + modelGraderTokenUsagePerModel: JsonField + ) = apply { this.modelGraderTokenUsagePerModel = modelGraderTokenUsagePerModel } + + fun reward(reward: Double) = reward(JsonField.of(reward)) + + /** + * Sets [Builder.reward] to an arbitrary JSON value. + * + * You should usually call [Builder.reward] with a well-typed [Double] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun reward(reward: JsonField) = apply { this.reward = reward } + + fun subRewards(subRewards: SubRewards) = subRewards(JsonField.of(subRewards)) + + /** + * Sets [Builder.subRewards] to an arbitrary JSON value. + * + * You should usually call [Builder.subRewards] with a well-typed [SubRewards] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun subRewards(subRewards: JsonField) = apply { this.subRewards = subRewards } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GraderRunResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .metadata() + * .modelGraderTokenUsagePerModel() + * .reward() + * .subRewards() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GraderRunResponse = + GraderRunResponse( + checkRequired("metadata", metadata), + checkRequired("modelGraderTokenUsagePerModel", modelGraderTokenUsagePerModel), + checkRequired("reward", reward), + checkRequired("subRewards", subRewards), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): GraderRunResponse = apply { + if (validated) { + return@apply + } + + metadata().validate() + modelGraderTokenUsagePerModel().validate() + reward() + subRewards().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (metadata.asKnown().getOrNull()?.validity() ?: 0) + + (modelGraderTokenUsagePerModel.asKnown().getOrNull()?.validity() ?: 0) + + (if (reward.asKnown().isPresent) 1 else 0) + + (subRewards.asKnown().getOrNull()?.validity() ?: 0) + + class Metadata + private constructor( + private val errors: JsonField, + private val executionTime: JsonField, + private val name: JsonField, + private val sampledModelName: JsonField, + private val scores: JsonField, + private val tokenUsage: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("errors") @ExcludeMissing errors: JsonField = JsonMissing.of(), + @JsonProperty("execution_time") + @ExcludeMissing + executionTime: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("sampled_model_name") + @ExcludeMissing + sampledModelName: JsonField = JsonMissing.of(), + @JsonProperty("scores") @ExcludeMissing scores: JsonField = JsonMissing.of(), + @JsonProperty("token_usage") + @ExcludeMissing + tokenUsage: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this( + errors, + executionTime, + name, + sampledModelName, + scores, + tokenUsage, + type, + mutableMapOf(), + ) + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun errors(): Errors = errors.getRequired("errors") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun executionTime(): Double = executionTime.getRequired("execution_time") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun name(): String = name.getRequired("name") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun sampledModelName(): Optional = + sampledModelName.getOptional("sampled_model_name") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun scores(): Scores = scores.getRequired("scores") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun tokenUsage(): Optional = tokenUsage.getOptional("token_usage") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun type(): String = type.getRequired("type") + + /** + * Returns the raw JSON value of [errors]. + * + * Unlike [errors], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("errors") @ExcludeMissing fun _errors(): JsonField = errors + + /** + * Returns the raw JSON value of [executionTime]. + * + * Unlike [executionTime], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("execution_time") + @ExcludeMissing + fun _executionTime(): JsonField = executionTime + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [sampledModelName]. + * + * Unlike [sampledModelName], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("sampled_model_name") + @ExcludeMissing + fun _sampledModelName(): JsonField = sampledModelName + + /** + * Returns the raw JSON value of [scores]. + * + * Unlike [scores], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("scores") @ExcludeMissing fun _scores(): JsonField = scores + + /** + * Returns the raw JSON value of [tokenUsage]. + * + * Unlike [tokenUsage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("token_usage") @ExcludeMissing fun _tokenUsage(): JsonField = tokenUsage + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Metadata]. + * + * The following fields are required: + * ```java + * .errors() + * .executionTime() + * .name() + * .sampledModelName() + * .scores() + * .tokenUsage() + * .type() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Metadata]. */ + class Builder internal constructor() { + + private var errors: JsonField? = null + private var executionTime: JsonField? = null + private var name: JsonField? = null + private var sampledModelName: JsonField? = null + private var scores: JsonField? = null + private var tokenUsage: JsonField? = null + private var type: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(metadata: Metadata) = apply { + errors = metadata.errors + executionTime = metadata.executionTime + name = metadata.name + sampledModelName = metadata.sampledModelName + scores = metadata.scores + tokenUsage = metadata.tokenUsage + type = metadata.type + additionalProperties = metadata.additionalProperties.toMutableMap() + } + + fun errors(errors: Errors) = errors(JsonField.of(errors)) + + /** + * Sets [Builder.errors] to an arbitrary JSON value. + * + * You should usually call [Builder.errors] with a well-typed [Errors] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun errors(errors: JsonField) = apply { this.errors = errors } + + fun executionTime(executionTime: Double) = executionTime(JsonField.of(executionTime)) + + /** + * Sets [Builder.executionTime] to an arbitrary JSON value. + * + * You should usually call [Builder.executionTime] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun executionTime(executionTime: JsonField) = apply { + this.executionTime = executionTime + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun sampledModelName(sampledModelName: String?) = + sampledModelName(JsonField.ofNullable(sampledModelName)) + + /** + * Alias for calling [Builder.sampledModelName] with `sampledModelName.orElse(null)`. + */ + fun sampledModelName(sampledModelName: Optional) = + sampledModelName(sampledModelName.getOrNull()) + + /** + * Sets [Builder.sampledModelName] to an arbitrary JSON value. + * + * You should usually call [Builder.sampledModelName] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun sampledModelName(sampledModelName: JsonField) = apply { + this.sampledModelName = sampledModelName + } + + fun scores(scores: Scores) = scores(JsonField.of(scores)) + + /** + * Sets [Builder.scores] to an arbitrary JSON value. + * + * You should usually call [Builder.scores] with a well-typed [Scores] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun scores(scores: JsonField) = apply { this.scores = scores } + + fun tokenUsage(tokenUsage: Long?) = tokenUsage(JsonField.ofNullable(tokenUsage)) + + /** + * Alias for [Builder.tokenUsage]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tokenUsage(tokenUsage: Long) = tokenUsage(tokenUsage as Long?) + + /** Alias for calling [Builder.tokenUsage] with `tokenUsage.orElse(null)`. */ + fun tokenUsage(tokenUsage: Optional) = tokenUsage(tokenUsage.getOrNull()) + + /** + * Sets [Builder.tokenUsage] to an arbitrary JSON value. + * + * You should usually call [Builder.tokenUsage] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tokenUsage(tokenUsage: JsonField) = apply { this.tokenUsage = tokenUsage } + + fun type(type: String) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Metadata]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .errors() + * .executionTime() + * .name() + * .sampledModelName() + * .scores() + * .tokenUsage() + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Metadata = + Metadata( + checkRequired("errors", errors), + checkRequired("executionTime", executionTime), + checkRequired("name", name), + checkRequired("sampledModelName", sampledModelName), + checkRequired("scores", scores), + checkRequired("tokenUsage", tokenUsage), + checkRequired("type", type), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Metadata = apply { + if (validated) { + return@apply + } + + errors().validate() + executionTime() + name() + sampledModelName() + scores().validate() + tokenUsage() + type() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (errors.asKnown().getOrNull()?.validity() ?: 0) + + (if (executionTime.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (sampledModelName.asKnown().isPresent) 1 else 0) + + (scores.asKnown().getOrNull()?.validity() ?: 0) + + (if (tokenUsage.asKnown().isPresent) 1 else 0) + + (if (type.asKnown().isPresent) 1 else 0) + + class Errors + private constructor( + private val formulaParseError: JsonField, + private val invalidVariableError: JsonField, + private val modelGraderParseError: JsonField, + private val modelGraderRefusalError: JsonField, + private val modelGraderServerError: JsonField, + private val modelGraderServerErrorDetails: JsonField, + private val otherError: JsonField, + private val pythonGraderRuntimeError: JsonField, + private val pythonGraderRuntimeErrorDetails: JsonField, + private val pythonGraderServerError: JsonField, + private val pythonGraderServerErrorType: JsonField, + private val sampleParseError: JsonField, + private val truncatedObservationError: JsonField, + private val unresponsiveRewardError: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("formula_parse_error") + @ExcludeMissing + formulaParseError: JsonField = JsonMissing.of(), + @JsonProperty("invalid_variable_error") + @ExcludeMissing + invalidVariableError: JsonField = JsonMissing.of(), + @JsonProperty("model_grader_parse_error") + @ExcludeMissing + modelGraderParseError: JsonField = JsonMissing.of(), + @JsonProperty("model_grader_refusal_error") + @ExcludeMissing + modelGraderRefusalError: JsonField = JsonMissing.of(), + @JsonProperty("model_grader_server_error") + @ExcludeMissing + modelGraderServerError: JsonField = JsonMissing.of(), + @JsonProperty("model_grader_server_error_details") + @ExcludeMissing + modelGraderServerErrorDetails: JsonField = JsonMissing.of(), + @JsonProperty("other_error") + @ExcludeMissing + otherError: JsonField = JsonMissing.of(), + @JsonProperty("python_grader_runtime_error") + @ExcludeMissing + pythonGraderRuntimeError: JsonField = JsonMissing.of(), + @JsonProperty("python_grader_runtime_error_details") + @ExcludeMissing + pythonGraderRuntimeErrorDetails: JsonField = JsonMissing.of(), + @JsonProperty("python_grader_server_error") + @ExcludeMissing + pythonGraderServerError: JsonField = JsonMissing.of(), + @JsonProperty("python_grader_server_error_type") + @ExcludeMissing + pythonGraderServerErrorType: JsonField = JsonMissing.of(), + @JsonProperty("sample_parse_error") + @ExcludeMissing + sampleParseError: JsonField = JsonMissing.of(), + @JsonProperty("truncated_observation_error") + @ExcludeMissing + truncatedObservationError: JsonField = JsonMissing.of(), + @JsonProperty("unresponsive_reward_error") + @ExcludeMissing + unresponsiveRewardError: JsonField = JsonMissing.of(), + ) : this( + formulaParseError, + invalidVariableError, + modelGraderParseError, + modelGraderRefusalError, + modelGraderServerError, + modelGraderServerErrorDetails, + otherError, + pythonGraderRuntimeError, + pythonGraderRuntimeErrorDetails, + pythonGraderServerError, + pythonGraderServerErrorType, + sampleParseError, + truncatedObservationError, + unresponsiveRewardError, + mutableMapOf(), + ) + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun formulaParseError(): Boolean = formulaParseError.getRequired("formula_parse_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun invalidVariableError(): Boolean = + invalidVariableError.getRequired("invalid_variable_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun modelGraderParseError(): Boolean = + modelGraderParseError.getRequired("model_grader_parse_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun modelGraderRefusalError(): Boolean = + modelGraderRefusalError.getRequired("model_grader_refusal_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun modelGraderServerError(): Boolean = + modelGraderServerError.getRequired("model_grader_server_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun modelGraderServerErrorDetails(): Optional = + modelGraderServerErrorDetails.getOptional("model_grader_server_error_details") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun otherError(): Boolean = otherError.getRequired("other_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun pythonGraderRuntimeError(): Boolean = + pythonGraderRuntimeError.getRequired("python_grader_runtime_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pythonGraderRuntimeErrorDetails(): Optional = + pythonGraderRuntimeErrorDetails.getOptional("python_grader_runtime_error_details") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun pythonGraderServerError(): Boolean = + pythonGraderServerError.getRequired("python_grader_server_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun pythonGraderServerErrorType(): Optional = + pythonGraderServerErrorType.getOptional("python_grader_server_error_type") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun sampleParseError(): Boolean = sampleParseError.getRequired("sample_parse_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun truncatedObservationError(): Boolean = + truncatedObservationError.getRequired("truncated_observation_error") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun unresponsiveRewardError(): Boolean = + unresponsiveRewardError.getRequired("unresponsive_reward_error") + + /** + * Returns the raw JSON value of [formulaParseError]. + * + * Unlike [formulaParseError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("formula_parse_error") + @ExcludeMissing + fun _formulaParseError(): JsonField = formulaParseError + + /** + * Returns the raw JSON value of [invalidVariableError]. + * + * Unlike [invalidVariableError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("invalid_variable_error") + @ExcludeMissing + fun _invalidVariableError(): JsonField = invalidVariableError + + /** + * Returns the raw JSON value of [modelGraderParseError]. + * + * Unlike [modelGraderParseError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("model_grader_parse_error") + @ExcludeMissing + fun _modelGraderParseError(): JsonField = modelGraderParseError + + /** + * Returns the raw JSON value of [modelGraderRefusalError]. + * + * Unlike [modelGraderRefusalError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("model_grader_refusal_error") + @ExcludeMissing + fun _modelGraderRefusalError(): JsonField = modelGraderRefusalError + + /** + * Returns the raw JSON value of [modelGraderServerError]. + * + * Unlike [modelGraderServerError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("model_grader_server_error") + @ExcludeMissing + fun _modelGraderServerError(): JsonField = modelGraderServerError + + /** + * Returns the raw JSON value of [modelGraderServerErrorDetails]. + * + * Unlike [modelGraderServerErrorDetails], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("model_grader_server_error_details") + @ExcludeMissing + fun _modelGraderServerErrorDetails(): JsonField = modelGraderServerErrorDetails + + /** + * Returns the raw JSON value of [otherError]. + * + * Unlike [otherError], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("other_error") + @ExcludeMissing + fun _otherError(): JsonField = otherError + + /** + * Returns the raw JSON value of [pythonGraderRuntimeError]. + * + * Unlike [pythonGraderRuntimeError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("python_grader_runtime_error") + @ExcludeMissing + fun _pythonGraderRuntimeError(): JsonField = pythonGraderRuntimeError + + /** + * Returns the raw JSON value of [pythonGraderRuntimeErrorDetails]. + * + * Unlike [pythonGraderRuntimeErrorDetails], this method doesn't throw if the JSON field + * has an unexpected type. + */ + @JsonProperty("python_grader_runtime_error_details") + @ExcludeMissing + fun _pythonGraderRuntimeErrorDetails(): JsonField = + pythonGraderRuntimeErrorDetails + + /** + * Returns the raw JSON value of [pythonGraderServerError]. + * + * Unlike [pythonGraderServerError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("python_grader_server_error") + @ExcludeMissing + fun _pythonGraderServerError(): JsonField = pythonGraderServerError + + /** + * Returns the raw JSON value of [pythonGraderServerErrorType]. + * + * Unlike [pythonGraderServerErrorType], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("python_grader_server_error_type") + @ExcludeMissing + fun _pythonGraderServerErrorType(): JsonField = pythonGraderServerErrorType + + /** + * Returns the raw JSON value of [sampleParseError]. + * + * Unlike [sampleParseError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("sample_parse_error") + @ExcludeMissing + fun _sampleParseError(): JsonField = sampleParseError + + /** + * Returns the raw JSON value of [truncatedObservationError]. + * + * Unlike [truncatedObservationError], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("truncated_observation_error") + @ExcludeMissing + fun _truncatedObservationError(): JsonField = truncatedObservationError + + /** + * Returns the raw JSON value of [unresponsiveRewardError]. + * + * Unlike [unresponsiveRewardError], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("unresponsive_reward_error") + @ExcludeMissing + fun _unresponsiveRewardError(): JsonField = unresponsiveRewardError + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Errors]. + * + * The following fields are required: + * ```java + * .formulaParseError() + * .invalidVariableError() + * .modelGraderParseError() + * .modelGraderRefusalError() + * .modelGraderServerError() + * .modelGraderServerErrorDetails() + * .otherError() + * .pythonGraderRuntimeError() + * .pythonGraderRuntimeErrorDetails() + * .pythonGraderServerError() + * .pythonGraderServerErrorType() + * .sampleParseError() + * .truncatedObservationError() + * .unresponsiveRewardError() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Errors]. */ + class Builder internal constructor() { + + private var formulaParseError: JsonField? = null + private var invalidVariableError: JsonField? = null + private var modelGraderParseError: JsonField? = null + private var modelGraderRefusalError: JsonField? = null + private var modelGraderServerError: JsonField? = null + private var modelGraderServerErrorDetails: JsonField? = null + private var otherError: JsonField? = null + private var pythonGraderRuntimeError: JsonField? = null + private var pythonGraderRuntimeErrorDetails: JsonField? = null + private var pythonGraderServerError: JsonField? = null + private var pythonGraderServerErrorType: JsonField? = null + private var sampleParseError: JsonField? = null + private var truncatedObservationError: JsonField? = null + private var unresponsiveRewardError: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(errors: Errors) = apply { + formulaParseError = errors.formulaParseError + invalidVariableError = errors.invalidVariableError + modelGraderParseError = errors.modelGraderParseError + modelGraderRefusalError = errors.modelGraderRefusalError + modelGraderServerError = errors.modelGraderServerError + modelGraderServerErrorDetails = errors.modelGraderServerErrorDetails + otherError = errors.otherError + pythonGraderRuntimeError = errors.pythonGraderRuntimeError + pythonGraderRuntimeErrorDetails = errors.pythonGraderRuntimeErrorDetails + pythonGraderServerError = errors.pythonGraderServerError + pythonGraderServerErrorType = errors.pythonGraderServerErrorType + sampleParseError = errors.sampleParseError + truncatedObservationError = errors.truncatedObservationError + unresponsiveRewardError = errors.unresponsiveRewardError + additionalProperties = errors.additionalProperties.toMutableMap() + } + + fun formulaParseError(formulaParseError: Boolean) = + formulaParseError(JsonField.of(formulaParseError)) + + /** + * Sets [Builder.formulaParseError] to an arbitrary JSON value. + * + * You should usually call [Builder.formulaParseError] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun formulaParseError(formulaParseError: JsonField) = apply { + this.formulaParseError = formulaParseError + } + + fun invalidVariableError(invalidVariableError: Boolean) = + invalidVariableError(JsonField.of(invalidVariableError)) + + /** + * Sets [Builder.invalidVariableError] to an arbitrary JSON value. + * + * You should usually call [Builder.invalidVariableError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun invalidVariableError(invalidVariableError: JsonField) = apply { + this.invalidVariableError = invalidVariableError + } + + fun modelGraderParseError(modelGraderParseError: Boolean) = + modelGraderParseError(JsonField.of(modelGraderParseError)) + + /** + * Sets [Builder.modelGraderParseError] to an arbitrary JSON value. + * + * You should usually call [Builder.modelGraderParseError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun modelGraderParseError(modelGraderParseError: JsonField) = apply { + this.modelGraderParseError = modelGraderParseError + } + + fun modelGraderRefusalError(modelGraderRefusalError: Boolean) = + modelGraderRefusalError(JsonField.of(modelGraderRefusalError)) + + /** + * Sets [Builder.modelGraderRefusalError] to an arbitrary JSON value. + * + * You should usually call [Builder.modelGraderRefusalError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun modelGraderRefusalError(modelGraderRefusalError: JsonField) = apply { + this.modelGraderRefusalError = modelGraderRefusalError + } + + fun modelGraderServerError(modelGraderServerError: Boolean) = + modelGraderServerError(JsonField.of(modelGraderServerError)) + + /** + * Sets [Builder.modelGraderServerError] to an arbitrary JSON value. + * + * You should usually call [Builder.modelGraderServerError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun modelGraderServerError(modelGraderServerError: JsonField) = apply { + this.modelGraderServerError = modelGraderServerError + } + + fun modelGraderServerErrorDetails(modelGraderServerErrorDetails: String?) = + modelGraderServerErrorDetails( + JsonField.ofNullable(modelGraderServerErrorDetails) + ) + + /** + * Alias for calling [Builder.modelGraderServerErrorDetails] with + * `modelGraderServerErrorDetails.orElse(null)`. + */ + fun modelGraderServerErrorDetails(modelGraderServerErrorDetails: Optional) = + modelGraderServerErrorDetails(modelGraderServerErrorDetails.getOrNull()) + + /** + * Sets [Builder.modelGraderServerErrorDetails] to an arbitrary JSON value. + * + * You should usually call [Builder.modelGraderServerErrorDetails] with a well-typed + * [String] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun modelGraderServerErrorDetails( + modelGraderServerErrorDetails: JsonField + ) = apply { this.modelGraderServerErrorDetails = modelGraderServerErrorDetails } + + fun otherError(otherError: Boolean) = otherError(JsonField.of(otherError)) + + /** + * Sets [Builder.otherError] to an arbitrary JSON value. + * + * You should usually call [Builder.otherError] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun otherError(otherError: JsonField) = apply { + this.otherError = otherError + } + + fun pythonGraderRuntimeError(pythonGraderRuntimeError: Boolean) = + pythonGraderRuntimeError(JsonField.of(pythonGraderRuntimeError)) + + /** + * Sets [Builder.pythonGraderRuntimeError] to an arbitrary JSON value. + * + * You should usually call [Builder.pythonGraderRuntimeError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun pythonGraderRuntimeError(pythonGraderRuntimeError: JsonField) = apply { + this.pythonGraderRuntimeError = pythonGraderRuntimeError + } + + fun pythonGraderRuntimeErrorDetails(pythonGraderRuntimeErrorDetails: String?) = + pythonGraderRuntimeErrorDetails( + JsonField.ofNullable(pythonGraderRuntimeErrorDetails) + ) + + /** + * Alias for calling [Builder.pythonGraderRuntimeErrorDetails] with + * `pythonGraderRuntimeErrorDetails.orElse(null)`. + */ + fun pythonGraderRuntimeErrorDetails( + pythonGraderRuntimeErrorDetails: Optional + ) = pythonGraderRuntimeErrorDetails(pythonGraderRuntimeErrorDetails.getOrNull()) + + /** + * Sets [Builder.pythonGraderRuntimeErrorDetails] to an arbitrary JSON value. + * + * You should usually call [Builder.pythonGraderRuntimeErrorDetails] with a + * well-typed [String] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun pythonGraderRuntimeErrorDetails( + pythonGraderRuntimeErrorDetails: JsonField + ) = apply { this.pythonGraderRuntimeErrorDetails = pythonGraderRuntimeErrorDetails } + + fun pythonGraderServerError(pythonGraderServerError: Boolean) = + pythonGraderServerError(JsonField.of(pythonGraderServerError)) + + /** + * Sets [Builder.pythonGraderServerError] to an arbitrary JSON value. + * + * You should usually call [Builder.pythonGraderServerError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun pythonGraderServerError(pythonGraderServerError: JsonField) = apply { + this.pythonGraderServerError = pythonGraderServerError + } + + fun pythonGraderServerErrorType(pythonGraderServerErrorType: String?) = + pythonGraderServerErrorType(JsonField.ofNullable(pythonGraderServerErrorType)) + + /** + * Alias for calling [Builder.pythonGraderServerErrorType] with + * `pythonGraderServerErrorType.orElse(null)`. + */ + fun pythonGraderServerErrorType(pythonGraderServerErrorType: Optional) = + pythonGraderServerErrorType(pythonGraderServerErrorType.getOrNull()) + + /** + * Sets [Builder.pythonGraderServerErrorType] to an arbitrary JSON value. + * + * You should usually call [Builder.pythonGraderServerErrorType] with a well-typed + * [String] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun pythonGraderServerErrorType(pythonGraderServerErrorType: JsonField) = + apply { + this.pythonGraderServerErrorType = pythonGraderServerErrorType + } + + fun sampleParseError(sampleParseError: Boolean) = + sampleParseError(JsonField.of(sampleParseError)) + + /** + * Sets [Builder.sampleParseError] to an arbitrary JSON value. + * + * You should usually call [Builder.sampleParseError] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun sampleParseError(sampleParseError: JsonField) = apply { + this.sampleParseError = sampleParseError + } + + fun truncatedObservationError(truncatedObservationError: Boolean) = + truncatedObservationError(JsonField.of(truncatedObservationError)) + + /** + * Sets [Builder.truncatedObservationError] to an arbitrary JSON value. + * + * You should usually call [Builder.truncatedObservationError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun truncatedObservationError(truncatedObservationError: JsonField) = + apply { + this.truncatedObservationError = truncatedObservationError + } + + fun unresponsiveRewardError(unresponsiveRewardError: Boolean) = + unresponsiveRewardError(JsonField.of(unresponsiveRewardError)) + + /** + * Sets [Builder.unresponsiveRewardError] to an arbitrary JSON value. + * + * You should usually call [Builder.unresponsiveRewardError] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun unresponsiveRewardError(unresponsiveRewardError: JsonField) = apply { + this.unresponsiveRewardError = unresponsiveRewardError + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Errors]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .formulaParseError() + * .invalidVariableError() + * .modelGraderParseError() + * .modelGraderRefusalError() + * .modelGraderServerError() + * .modelGraderServerErrorDetails() + * .otherError() + * .pythonGraderRuntimeError() + * .pythonGraderRuntimeErrorDetails() + * .pythonGraderServerError() + * .pythonGraderServerErrorType() + * .sampleParseError() + * .truncatedObservationError() + * .unresponsiveRewardError() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Errors = + Errors( + checkRequired("formulaParseError", formulaParseError), + checkRequired("invalidVariableError", invalidVariableError), + checkRequired("modelGraderParseError", modelGraderParseError), + checkRequired("modelGraderRefusalError", modelGraderRefusalError), + checkRequired("modelGraderServerError", modelGraderServerError), + checkRequired( + "modelGraderServerErrorDetails", + modelGraderServerErrorDetails, + ), + checkRequired("otherError", otherError), + checkRequired("pythonGraderRuntimeError", pythonGraderRuntimeError), + checkRequired( + "pythonGraderRuntimeErrorDetails", + pythonGraderRuntimeErrorDetails, + ), + checkRequired("pythonGraderServerError", pythonGraderServerError), + checkRequired("pythonGraderServerErrorType", pythonGraderServerErrorType), + checkRequired("sampleParseError", sampleParseError), + checkRequired("truncatedObservationError", truncatedObservationError), + checkRequired("unresponsiveRewardError", unresponsiveRewardError), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Errors = apply { + if (validated) { + return@apply + } + + formulaParseError() + invalidVariableError() + modelGraderParseError() + modelGraderRefusalError() + modelGraderServerError() + modelGraderServerErrorDetails() + otherError() + pythonGraderRuntimeError() + pythonGraderRuntimeErrorDetails() + pythonGraderServerError() + pythonGraderServerErrorType() + sampleParseError() + truncatedObservationError() + unresponsiveRewardError() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (formulaParseError.asKnown().isPresent) 1 else 0) + + (if (invalidVariableError.asKnown().isPresent) 1 else 0) + + (if (modelGraderParseError.asKnown().isPresent) 1 else 0) + + (if (modelGraderRefusalError.asKnown().isPresent) 1 else 0) + + (if (modelGraderServerError.asKnown().isPresent) 1 else 0) + + (if (modelGraderServerErrorDetails.asKnown().isPresent) 1 else 0) + + (if (otherError.asKnown().isPresent) 1 else 0) + + (if (pythonGraderRuntimeError.asKnown().isPresent) 1 else 0) + + (if (pythonGraderRuntimeErrorDetails.asKnown().isPresent) 1 else 0) + + (if (pythonGraderServerError.asKnown().isPresent) 1 else 0) + + (if (pythonGraderServerErrorType.asKnown().isPresent) 1 else 0) + + (if (sampleParseError.asKnown().isPresent) 1 else 0) + + (if (truncatedObservationError.asKnown().isPresent) 1 else 0) + + (if (unresponsiveRewardError.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Errors && formulaParseError == other.formulaParseError && invalidVariableError == other.invalidVariableError && modelGraderParseError == other.modelGraderParseError && modelGraderRefusalError == other.modelGraderRefusalError && modelGraderServerError == other.modelGraderServerError && modelGraderServerErrorDetails == other.modelGraderServerErrorDetails && otherError == other.otherError && pythonGraderRuntimeError == other.pythonGraderRuntimeError && pythonGraderRuntimeErrorDetails == other.pythonGraderRuntimeErrorDetails && pythonGraderServerError == other.pythonGraderServerError && pythonGraderServerErrorType == other.pythonGraderServerErrorType && sampleParseError == other.sampleParseError && truncatedObservationError == other.truncatedObservationError && unresponsiveRewardError == other.unresponsiveRewardError && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(formulaParseError, invalidVariableError, modelGraderParseError, modelGraderRefusalError, modelGraderServerError, modelGraderServerErrorDetails, otherError, pythonGraderRuntimeError, pythonGraderRuntimeErrorDetails, pythonGraderServerError, pythonGraderServerErrorType, sampleParseError, truncatedObservationError, unresponsiveRewardError, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Errors{formulaParseError=$formulaParseError, invalidVariableError=$invalidVariableError, modelGraderParseError=$modelGraderParseError, modelGraderRefusalError=$modelGraderRefusalError, modelGraderServerError=$modelGraderServerError, modelGraderServerErrorDetails=$modelGraderServerErrorDetails, otherError=$otherError, pythonGraderRuntimeError=$pythonGraderRuntimeError, pythonGraderRuntimeErrorDetails=$pythonGraderRuntimeErrorDetails, pythonGraderServerError=$pythonGraderServerError, pythonGraderServerErrorType=$pythonGraderServerErrorType, sampleParseError=$sampleParseError, truncatedObservationError=$truncatedObservationError, unresponsiveRewardError=$unresponsiveRewardError, additionalProperties=$additionalProperties}" + } + + class Scores + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Scores]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Scores]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(scores: Scores) = apply { + additionalProperties = scores.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Scores]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Scores = Scores(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Scores = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Scores && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = "Scores{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Metadata && errors == other.errors && executionTime == other.executionTime && name == other.name && sampledModelName == other.sampledModelName && scores == other.scores && tokenUsage == other.tokenUsage && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(errors, executionTime, name, sampledModelName, scores, tokenUsage, type, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Metadata{errors=$errors, executionTime=$executionTime, name=$name, sampledModelName=$sampledModelName, scores=$scores, tokenUsage=$tokenUsage, type=$type, additionalProperties=$additionalProperties}" + } + + class ModelGraderTokenUsagePerModel + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [ModelGraderTokenUsagePerModel]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ModelGraderTokenUsagePerModel]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(modelGraderTokenUsagePerModel: ModelGraderTokenUsagePerModel) = + apply { + additionalProperties = + modelGraderTokenUsagePerModel.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ModelGraderTokenUsagePerModel]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ModelGraderTokenUsagePerModel = + ModelGraderTokenUsagePerModel(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): ModelGraderTokenUsagePerModel = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ModelGraderTokenUsagePerModel && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ModelGraderTokenUsagePerModel{additionalProperties=$additionalProperties}" + } + + class SubRewards + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SubRewards]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SubRewards]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(subRewards: SubRewards) = apply { + additionalProperties = subRewards.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SubRewards]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SubRewards = SubRewards(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): SubRewards = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is SubRewards && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = "SubRewards{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GraderRunResponse && metadata == other.metadata && modelGraderTokenUsagePerModel == other.modelGraderTokenUsagePerModel && reward == other.reward && subRewards == other.subRewards && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(metadata, modelGraderTokenUsagePerModel, reward, subRewards, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GraderRunResponse{metadata=$metadata, modelGraderTokenUsagePerModel=$modelGraderTokenUsagePerModel, reward=$reward, subRewards=$subRewards, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateParams.kt new file mode 100644 index 000000000..329bf9cb1 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateParams.kt @@ -0,0 +1,747 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.Params +import com.openai.core.allMaxBy +import com.openai.core.checkRequired +import com.openai.core.getOrThrow +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.graders.gradermodels.MultiGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Validate a grader. */ +class GraderValidateParams +private constructor( + private val body: Body, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, +) : Params { + + /** + * The grader used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun grader(): Grader = body.grader() + + /** + * Returns the raw JSON value of [grader]. + * + * Unlike [grader], this method doesn't throw if the JSON field has an unexpected type. + */ + fun _grader(): JsonField = body._grader() + + fun _additionalBodyProperties(): Map = body._additionalProperties() + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [GraderValidateParams]. + * + * The following fields are required: + * ```java + * .grader() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GraderValidateParams]. */ + class Builder internal constructor() { + + private var body: Body.Builder = Body.builder() + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + + @JvmSynthetic + internal fun from(graderValidateParams: GraderValidateParams) = apply { + body = graderValidateParams.body.toBuilder() + additionalHeaders = graderValidateParams.additionalHeaders.toBuilder() + additionalQueryParams = graderValidateParams.additionalQueryParams.toBuilder() + } + + /** + * Sets the entire request body. + * + * This is generally only useful if you are already constructing the body separately. + * Otherwise, it's more convenient to use the top-level setters instead: + * - [grader] + */ + fun body(body: Body) = apply { this.body = body.toBuilder() } + + /** The grader used for the fine-tuning job. */ + fun grader(grader: Grader) = apply { body.grader(grader) } + + /** + * Sets [Builder.grader] to an arbitrary JSON value. + * + * You should usually call [Builder.grader] with a well-typed [Grader] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun grader(grader: JsonField) = apply { body.grader(grader) } + + /** Alias for calling [grader] with `Grader.ofStringCheck(stringCheck)`. */ + fun grader(stringCheck: StringCheckGrader) = apply { body.grader(stringCheck) } + + /** Alias for calling [grader] with `Grader.ofTextSimilarity(textSimilarity)`. */ + fun grader(textSimilarity: TextSimilarityGrader) = apply { body.grader(textSimilarity) } + + /** Alias for calling [grader] with `Grader.ofPython(python)`. */ + fun grader(python: PythonGrader) = apply { body.grader(python) } + + /** Alias for calling [grader] with `Grader.ofScoreModel(scoreModel)`. */ + fun grader(scoreModel: ScoreModelGrader) = apply { body.grader(scoreModel) } + + /** Alias for calling [grader] with `Grader.ofMulti(multi)`. */ + fun grader(multi: MultiGrader) = apply { body.grader(multi) } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + body.additionalProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + body.putAdditionalProperty(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + body.putAllAdditionalProperties(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { body.removeAdditionalProperty(key) } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + body.removeAllAdditionalProperties(keys) + } + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + /** + * Returns an immutable instance of [GraderValidateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .grader() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): GraderValidateParams = + GraderValidateParams( + body.build(), + additionalHeaders.build(), + additionalQueryParams.build(), + ) + } + + fun _body(): Body = body + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + class Body + private constructor( + private val grader: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("grader") @ExcludeMissing grader: JsonField = JsonMissing.of() + ) : this(grader, mutableMapOf()) + + /** + * The grader used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun grader(): Grader = grader.getRequired("grader") + + /** + * Returns the raw JSON value of [grader]. + * + * Unlike [grader], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("grader") @ExcludeMissing fun _grader(): JsonField = grader + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Body]. + * + * The following fields are required: + * ```java + * .grader() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Body]. */ + class Builder internal constructor() { + + private var grader: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(body: Body) = apply { + grader = body.grader + additionalProperties = body.additionalProperties.toMutableMap() + } + + /** The grader used for the fine-tuning job. */ + fun grader(grader: Grader) = grader(JsonField.of(grader)) + + /** + * Sets [Builder.grader] to an arbitrary JSON value. + * + * You should usually call [Builder.grader] with a well-typed [Grader] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun grader(grader: JsonField) = apply { this.grader = grader } + + /** Alias for calling [grader] with `Grader.ofStringCheck(stringCheck)`. */ + fun grader(stringCheck: StringCheckGrader) = grader(Grader.ofStringCheck(stringCheck)) + + /** Alias for calling [grader] with `Grader.ofTextSimilarity(textSimilarity)`. */ + fun grader(textSimilarity: TextSimilarityGrader) = + grader(Grader.ofTextSimilarity(textSimilarity)) + + /** Alias for calling [grader] with `Grader.ofPython(python)`. */ + fun grader(python: PythonGrader) = grader(Grader.ofPython(python)) + + /** Alias for calling [grader] with `Grader.ofScoreModel(scoreModel)`. */ + fun grader(scoreModel: ScoreModelGrader) = grader(Grader.ofScoreModel(scoreModel)) + + /** Alias for calling [grader] with `Grader.ofMulti(multi)`. */ + fun grader(multi: MultiGrader) = grader(Grader.ofMulti(multi)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Body]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .grader() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Body = + Body(checkRequired("grader", grader), additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): Body = apply { + if (validated) { + return@apply + } + + grader().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (grader.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Body && grader == other.grader && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(grader, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = "Body{grader=$grader, additionalProperties=$additionalProperties}" + } + + /** The grader used for the fine-tuning job. */ + @JsonDeserialize(using = Grader.Deserializer::class) + @JsonSerialize(using = Grader.Serializer::class) + class Grader + private constructor( + private val stringCheck: StringCheckGrader? = null, + private val textSimilarity: TextSimilarityGrader? = null, + private val python: PythonGrader? = null, + private val scoreModel: ScoreModelGrader? = null, + private val multi: MultiGrader? = null, + private val _json: JsonValue? = null, + ) { + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun textSimilarity(): Optional = Optional.ofNullable(textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + fun python(): Optional = Optional.ofNullable(python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun multi(): Optional = Optional.ofNullable(multi) + + fun isStringCheck(): Boolean = stringCheck != null + + fun isTextSimilarity(): Boolean = textSimilarity != null + + fun isPython(): Boolean = python != null + + fun isScoreModel(): Boolean = scoreModel != null + + fun isMulti(): Boolean = multi != null + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun asStringCheck(): StringCheckGrader = stringCheck.getOrThrow("stringCheck") + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun asTextSimilarity(): TextSimilarityGrader = textSimilarity.getOrThrow("textSimilarity") + + /** A PythonGrader object that runs a python script on the input. */ + fun asPython(): PythonGrader = python.getOrThrow("python") + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun asScoreModel(): ScoreModelGrader = scoreModel.getOrThrow("scoreModel") + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun asMulti(): MultiGrader = multi.getOrThrow("multi") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + stringCheck != null -> visitor.visitStringCheck(stringCheck) + textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) + python != null -> visitor.visitPython(python) + scoreModel != null -> visitor.visitScoreModel(scoreModel) + multi != null -> visitor.visitMulti(multi) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Grader = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) { + stringCheck.validate() + } + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) { + textSimilarity.validate() + } + + override fun visitPython(python: PythonGrader) { + python.validate() + } + + override fun visitScoreModel(scoreModel: ScoreModelGrader) { + scoreModel.validate() + } + + override fun visitMulti(multi: MultiGrader) { + multi.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) = + stringCheck.validity() + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) = + textSimilarity.validity() + + override fun visitPython(python: PythonGrader) = python.validity() + + override fun visitScoreModel(scoreModel: ScoreModelGrader) = + scoreModel.validity() + + override fun visitMulti(multi: MultiGrader) = multi.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Grader && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel && multi == other.multi /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(stringCheck, textSimilarity, python, scoreModel, multi) /* spotless:on */ + + override fun toString(): String = + when { + stringCheck != null -> "Grader{stringCheck=$stringCheck}" + textSimilarity != null -> "Grader{textSimilarity=$textSimilarity}" + python != null -> "Grader{python=$python}" + scoreModel != null -> "Grader{scoreModel=$scoreModel}" + multi != null -> "Grader{multi=$multi}" + _json != null -> "Grader{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Grader") + } + + companion object { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + @JvmStatic + fun ofStringCheck(stringCheck: StringCheckGrader) = Grader(stringCheck = stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + @JvmStatic + fun ofTextSimilarity(textSimilarity: TextSimilarityGrader) = + Grader(textSimilarity = textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + @JvmStatic fun ofPython(python: PythonGrader) = Grader(python = python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + @JvmStatic + fun ofScoreModel(scoreModel: ScoreModelGrader) = Grader(scoreModel = scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + @JvmStatic fun ofMulti(multi: MultiGrader) = Grader(multi = multi) + } + + /** An interface that defines how to map each variant of [Grader] to a value of type [T]. */ + interface Visitor { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + fun visitStringCheck(stringCheck: StringCheckGrader): T + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun visitTextSimilarity(textSimilarity: TextSimilarityGrader): T + + /** A PythonGrader object that runs a python script on the input. */ + fun visitPython(python: PythonGrader): T + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun visitScoreModel(scoreModel: ScoreModelGrader): T + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + fun visitMulti(multi: MultiGrader): T + + /** + * Maps an unknown variant of [Grader] to a value of type [T]. + * + * An instance of [Grader] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Grader: $json") + } + } + + internal class Deserializer : BaseDeserializer(Grader::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Grader { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(stringCheck = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(textSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(python = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(scoreModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(multi = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> Grader(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Grader::class) { + + override fun serialize( + value: Grader, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.stringCheck != null -> generator.writeObject(value.stringCheck) + value.textSimilarity != null -> generator.writeObject(value.textSimilarity) + value.python != null -> generator.writeObject(value.python) + value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.multi != null -> generator.writeObject(value.multi) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Grader") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GraderValidateParams && body == other.body && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(body, additionalHeaders, additionalQueryParams) /* spotless:on */ + + override fun toString() = + "GraderValidateParams{body=$body, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateResponse.kt new file mode 100644 index 000000000..c3229eb53 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateResponse.kt @@ -0,0 +1,478 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.allMaxBy +import com.openai.core.getOrThrow +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.graders.gradermodels.MultiGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +class GraderValidateResponse +private constructor( + private val grader: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("grader") @ExcludeMissing grader: JsonField = JsonMissing.of() + ) : this(grader, mutableMapOf()) + + /** + * The grader used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun grader(): Optional = grader.getOptional("grader") + + /** + * Returns the raw JSON value of [grader]. + * + * Unlike [grader], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("grader") @ExcludeMissing fun _grader(): JsonField = grader + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [GraderValidateResponse]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [GraderValidateResponse]. */ + class Builder internal constructor() { + + private var grader: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(graderValidateResponse: GraderValidateResponse) = apply { + grader = graderValidateResponse.grader + additionalProperties = graderValidateResponse.additionalProperties.toMutableMap() + } + + /** The grader used for the fine-tuning job. */ + fun grader(grader: Grader) = grader(JsonField.of(grader)) + + /** + * Sets [Builder.grader] to an arbitrary JSON value. + * + * You should usually call [Builder.grader] with a well-typed [Grader] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun grader(grader: JsonField) = apply { this.grader = grader } + + /** Alias for calling [grader] with `Grader.ofStringCheck(stringCheck)`. */ + fun grader(stringCheck: StringCheckGrader) = grader(Grader.ofStringCheck(stringCheck)) + + /** Alias for calling [grader] with `Grader.ofTextSimilarity(textSimilarity)`. */ + fun grader(textSimilarity: TextSimilarityGrader) = + grader(Grader.ofTextSimilarity(textSimilarity)) + + /** Alias for calling [grader] with `Grader.ofPython(python)`. */ + fun grader(python: PythonGrader) = grader(Grader.ofPython(python)) + + /** Alias for calling [grader] with `Grader.ofScoreModel(scoreModel)`. */ + fun grader(scoreModel: ScoreModelGrader) = grader(Grader.ofScoreModel(scoreModel)) + + /** Alias for calling [grader] with `Grader.ofMulti(multi)`. */ + fun grader(multi: MultiGrader) = grader(Grader.ofMulti(multi)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [GraderValidateResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): GraderValidateResponse = + GraderValidateResponse(grader, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): GraderValidateResponse = apply { + if (validated) { + return@apply + } + + grader().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = (grader.asKnown().getOrNull()?.validity() ?: 0) + + /** The grader used for the fine-tuning job. */ + @JsonDeserialize(using = Grader.Deserializer::class) + @JsonSerialize(using = Grader.Serializer::class) + class Grader + private constructor( + private val stringCheck: StringCheckGrader? = null, + private val textSimilarity: TextSimilarityGrader? = null, + private val python: PythonGrader? = null, + private val scoreModel: ScoreModelGrader? = null, + private val multi: MultiGrader? = null, + private val _json: JsonValue? = null, + ) { + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun textSimilarity(): Optional = Optional.ofNullable(textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + fun python(): Optional = Optional.ofNullable(python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun multi(): Optional = Optional.ofNullable(multi) + + fun isStringCheck(): Boolean = stringCheck != null + + fun isTextSimilarity(): Boolean = textSimilarity != null + + fun isPython(): Boolean = python != null + + fun isScoreModel(): Boolean = scoreModel != null + + fun isMulti(): Boolean = multi != null + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun asStringCheck(): StringCheckGrader = stringCheck.getOrThrow("stringCheck") + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun asTextSimilarity(): TextSimilarityGrader = textSimilarity.getOrThrow("textSimilarity") + + /** A PythonGrader object that runs a python script on the input. */ + fun asPython(): PythonGrader = python.getOrThrow("python") + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun asScoreModel(): ScoreModelGrader = scoreModel.getOrThrow("scoreModel") + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun asMulti(): MultiGrader = multi.getOrThrow("multi") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + stringCheck != null -> visitor.visitStringCheck(stringCheck) + textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) + python != null -> visitor.visitPython(python) + scoreModel != null -> visitor.visitScoreModel(scoreModel) + multi != null -> visitor.visitMulti(multi) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Grader = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) { + stringCheck.validate() + } + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) { + textSimilarity.validate() + } + + override fun visitPython(python: PythonGrader) { + python.validate() + } + + override fun visitScoreModel(scoreModel: ScoreModelGrader) { + scoreModel.validate() + } + + override fun visitMulti(multi: MultiGrader) { + multi.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) = + stringCheck.validity() + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) = + textSimilarity.validity() + + override fun visitPython(python: PythonGrader) = python.validity() + + override fun visitScoreModel(scoreModel: ScoreModelGrader) = + scoreModel.validity() + + override fun visitMulti(multi: MultiGrader) = multi.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Grader && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel && multi == other.multi /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(stringCheck, textSimilarity, python, scoreModel, multi) /* spotless:on */ + + override fun toString(): String = + when { + stringCheck != null -> "Grader{stringCheck=$stringCheck}" + textSimilarity != null -> "Grader{textSimilarity=$textSimilarity}" + python != null -> "Grader{python=$python}" + scoreModel != null -> "Grader{scoreModel=$scoreModel}" + multi != null -> "Grader{multi=$multi}" + _json != null -> "Grader{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Grader") + } + + companion object { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + @JvmStatic + fun ofStringCheck(stringCheck: StringCheckGrader) = Grader(stringCheck = stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + @JvmStatic + fun ofTextSimilarity(textSimilarity: TextSimilarityGrader) = + Grader(textSimilarity = textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + @JvmStatic fun ofPython(python: PythonGrader) = Grader(python = python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + @JvmStatic + fun ofScoreModel(scoreModel: ScoreModelGrader) = Grader(scoreModel = scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + @JvmStatic fun ofMulti(multi: MultiGrader) = Grader(multi = multi) + } + + /** An interface that defines how to map each variant of [Grader] to a value of type [T]. */ + interface Visitor { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + fun visitStringCheck(stringCheck: StringCheckGrader): T + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun visitTextSimilarity(textSimilarity: TextSimilarityGrader): T + + /** A PythonGrader object that runs a python script on the input. */ + fun visitPython(python: PythonGrader): T + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun visitScoreModel(scoreModel: ScoreModelGrader): T + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + fun visitMulti(multi: MultiGrader): T + + /** + * Maps an unknown variant of [Grader] to a value of type [T]. + * + * An instance of [Grader] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Grader: $json") + } + } + + internal class Deserializer : BaseDeserializer(Grader::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Grader { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(stringCheck = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(textSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(python = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(scoreModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(multi = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> Grader(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Grader::class) { + + override fun serialize( + value: Grader, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.stringCheck != null -> generator.writeObject(value.stringCheck) + value.textSimilarity != null -> generator.writeObject(value.textSimilarity) + value.python != null -> generator.writeObject(value.python) + value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.multi != null -> generator.writeObject(value.multi) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Grader") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is GraderValidateResponse && grader == other.grader && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(grader, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "GraderValidateResponse{grader=$grader, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePage.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePage.kt index ea6aeac9c..fd72758d2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePage.kt @@ -2,13 +2,12 @@ package com.openai.models.finetuning.checkpoints.permissions +import com.openai.core.AutoPager import com.openai.core.JsonValue +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.finetuning.checkpoints.PermissionService import java.util.Objects -import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [PermissionService.create] */ @@ -17,7 +16,7 @@ private constructor( private val service: PermissionService, private val params: PermissionCreateParams, private val response: PermissionCreatePageResponse, -) { +) : Page { /** * Delegates to [PermissionCreatePageResponse], but gracefully handles missing data. @@ -30,14 +29,16 @@ private constructor( /** @see [PermissionCreatePageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): Optional = - getNextPageParams().map { service.create(it) } + fun nextPageParams(): PermissionCreateParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): PermissionCreatePage = service.create(nextPageParams()) + + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): PermissionCreateParams = params @@ -106,26 +107,6 @@ private constructor( ) } - class AutoPager(private val firstPage: PermissionCreatePage) : - Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePageAsync.kt index 174dc4c7a..c67b8a800 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreatePageAsync.kt @@ -2,23 +2,24 @@ package com.openai.models.finetuning.checkpoints.permissions +import com.openai.core.AutoPagerAsync import com.openai.core.JsonValue +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.finetuning.checkpoints.PermissionServiceAsync import java.util.Objects -import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [PermissionServiceAsync.create] */ class PermissionCreatePageAsync private constructor( private val service: PermissionServiceAsync, + private val streamHandlerExecutor: Executor, private val params: PermissionCreateParams, private val response: PermissionCreatePageResponse, -) { +) : PageAsync { /** * Delegates to [PermissionCreatePageResponse], but gracefully handles missing data. @@ -31,16 +32,18 @@ private constructor( /** @see [PermissionCreatePageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.create(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + fun nextPageParams(): PermissionCreateParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): CompletableFuture = + service.create(nextPageParams()) + + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): PermissionCreateParams = params @@ -58,6 +61,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -69,18 +73,24 @@ private constructor( class Builder internal constructor() { private var service: PermissionServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: PermissionCreateParams? = null private var response: PermissionCreatePageResponse? = null @JvmSynthetic internal fun from(permissionCreatePageAsync: PermissionCreatePageAsync) = apply { service = permissionCreatePageAsync.service + streamHandlerExecutor = permissionCreatePageAsync.streamHandlerExecutor params = permissionCreatePageAsync.params response = permissionCreatePageAsync.response } fun service(service: PermissionServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: PermissionCreateParams) = apply { this.params = params } @@ -95,6 +105,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -104,50 +115,22 @@ private constructor( fun build(): PermissionCreatePageAsync = PermissionCreatePageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: PermissionCreatePageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (PermissionCreateResponse) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is PermissionCreatePageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is PermissionCreatePageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "PermissionCreatePageAsync{service=$service, params=$params, response=$response}" + "PermissionCreatePageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreateParams.kt index 6346ac328..dcbd6ccd9 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionCreateParams.kt @@ -19,6 +19,7 @@ import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException import java.util.Collections import java.util.Objects +import java.util.Optional import kotlin.jvm.optionals.getOrNull /** @@ -29,13 +30,13 @@ import kotlin.jvm.optionals.getOrNull */ class PermissionCreateParams private constructor( - private val fineTunedModelCheckpoint: String, + private val fineTunedModelCheckpoint: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun fineTunedModelCheckpoint(): String = fineTunedModelCheckpoint + fun fineTunedModelCheckpoint(): Optional = Optional.ofNullable(fineTunedModelCheckpoint) /** * The project identifiers to grant access to. @@ -67,7 +68,6 @@ private constructor( * * The following fields are required: * ```java - * .fineTunedModelCheckpoint() * .projectIds() * ``` */ @@ -90,10 +90,17 @@ private constructor( additionalQueryParams = permissionCreateParams.additionalQueryParams.toBuilder() } - fun fineTunedModelCheckpoint(fineTunedModelCheckpoint: String) = apply { + fun fineTunedModelCheckpoint(fineTunedModelCheckpoint: String?) = apply { this.fineTunedModelCheckpoint = fineTunedModelCheckpoint } + /** + * Alias for calling [Builder.fineTunedModelCheckpoint] with + * `fineTunedModelCheckpoint.orElse(null)`. + */ + fun fineTunedModelCheckpoint(fineTunedModelCheckpoint: Optional) = + fineTunedModelCheckpoint(fineTunedModelCheckpoint.getOrNull()) + /** * Sets the entire request body. * @@ -246,7 +253,6 @@ private constructor( * * The following fields are required: * ```java - * .fineTunedModelCheckpoint() * .projectIds() * ``` * @@ -254,7 +260,7 @@ private constructor( */ fun build(): PermissionCreateParams = PermissionCreateParams( - checkRequired("fineTunedModelCheckpoint", fineTunedModelCheckpoint), + fineTunedModelCheckpoint, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -265,7 +271,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fineTunedModelCheckpoint + 0 -> fineTunedModelCheckpoint ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionDeleteParams.kt index bf8173c54..ce09abfca 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionDeleteParams.kt @@ -10,6 +10,7 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). @@ -20,7 +21,7 @@ import java.util.Optional class PermissionDeleteParams private constructor( private val fineTunedModelCheckpoint: String, - private val permissionId: String, + private val permissionId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -28,7 +29,7 @@ private constructor( fun fineTunedModelCheckpoint(): String = fineTunedModelCheckpoint - fun permissionId(): String = permissionId + fun permissionId(): Optional = Optional.ofNullable(permissionId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -46,7 +47,6 @@ private constructor( * The following fields are required: * ```java * .fineTunedModelCheckpoint() - * .permissionId() * ``` */ @JvmStatic fun builder() = Builder() @@ -75,7 +75,10 @@ private constructor( this.fineTunedModelCheckpoint = fineTunedModelCheckpoint } - fun permissionId(permissionId: String) = apply { this.permissionId = permissionId } + fun permissionId(permissionId: String?) = apply { this.permissionId = permissionId } + + /** Alias for calling [Builder.permissionId] with `permissionId.orElse(null)`. */ + fun permissionId(permissionId: Optional) = permissionId(permissionId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -205,7 +208,6 @@ private constructor( * The following fields are required: * ```java * .fineTunedModelCheckpoint() - * .permissionId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -213,7 +215,7 @@ private constructor( fun build(): PermissionDeleteParams = PermissionDeleteParams( checkRequired("fineTunedModelCheckpoint", fineTunedModelCheckpoint), - checkRequired("permissionId", permissionId), + permissionId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -226,7 +228,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> fineTunedModelCheckpoint - 1 -> permissionId + 1 -> permissionId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionRetrieveParams.kt index e9276feef..2205d7673 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/checkpoints/permissions/PermissionRetrieveParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.errors.OpenAIInvalidDataException @@ -22,7 +21,7 @@ import kotlin.jvm.optionals.getOrNull */ class PermissionRetrieveParams private constructor( - private val fineTunedModelCheckpoint: String, + private val fineTunedModelCheckpoint: String?, private val after: String?, private val limit: Long?, private val order: Order?, @@ -31,7 +30,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun fineTunedModelCheckpoint(): String = fineTunedModelCheckpoint + fun fineTunedModelCheckpoint(): Optional = Optional.ofNullable(fineTunedModelCheckpoint) /** Identifier for the last permission ID from the previous pagination request. */ fun after(): Optional = Optional.ofNullable(after) @@ -53,14 +52,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [PermissionRetrieveParams]. - * - * The following fields are required: - * ```java - * .fineTunedModelCheckpoint() - * ``` - */ + @JvmStatic fun none(): PermissionRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [PermissionRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -86,10 +80,17 @@ private constructor( additionalQueryParams = permissionRetrieveParams.additionalQueryParams.toBuilder() } - fun fineTunedModelCheckpoint(fineTunedModelCheckpoint: String) = apply { + fun fineTunedModelCheckpoint(fineTunedModelCheckpoint: String?) = apply { this.fineTunedModelCheckpoint = fineTunedModelCheckpoint } + /** + * Alias for calling [Builder.fineTunedModelCheckpoint] with + * `fineTunedModelCheckpoint.orElse(null)`. + */ + fun fineTunedModelCheckpoint(fineTunedModelCheckpoint: Optional) = + fineTunedModelCheckpoint(fineTunedModelCheckpoint.getOrNull()) + /** Identifier for the last permission ID from the previous pagination request. */ fun after(after: String?) = apply { this.after = after } @@ -223,17 +224,10 @@ private constructor( * Returns an immutable instance of [PermissionRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fineTunedModelCheckpoint() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): PermissionRetrieveParams = PermissionRetrieveParams( - checkRequired("fineTunedModelCheckpoint", fineTunedModelCheckpoint), + fineTunedModelCheckpoint, after, limit, order, @@ -245,7 +239,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fineTunedModelCheckpoint + 0 -> fineTunedModelCheckpoint ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/FineTuningJob.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/FineTuningJob.kt index 9c99d13ca..5780ac73a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/FineTuningJob.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/FineTuningJob.kt @@ -26,6 +26,9 @@ import com.openai.core.checkRequired import com.openai.core.getOrThrow import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedMethod import java.util.Collections import java.util.Objects import java.util.Optional @@ -2357,20 +2360,32 @@ private constructor( /** The method used for fine-tuning. */ class Method private constructor( - private val dpo: JsonField, - private val supervised: JsonField, private val type: JsonField, + private val dpo: JsonField, + private val reinforcement: JsonField, + private val supervised: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("dpo") @ExcludeMissing dpo: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("dpo") @ExcludeMissing dpo: JsonField = JsonMissing.of(), + @JsonProperty("reinforcement") + @ExcludeMissing + reinforcement: JsonField = JsonMissing.of(), @JsonProperty("supervised") @ExcludeMissing - supervised: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(dpo, supervised, type, mutableMapOf()) + supervised: JsonField = JsonMissing.of(), + ) : this(type, dpo, reinforcement, supervised, mutableMapOf()) + + /** + * The type of method. Is either `supervised`, `dpo`, or `reinforcement`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun type(): Type = type.getRequired("type") /** * Configuration for the DPO fine-tuning method. @@ -2378,46 +2393,57 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun dpo(): Optional = dpo.getOptional("dpo") + fun dpo(): Optional = dpo.getOptional("dpo") /** - * Configuration for the supervised fine-tuning method. + * Configuration for the reinforcement fine-tuning method. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun supervised(): Optional = supervised.getOptional("supervised") + fun reinforcement(): Optional = + reinforcement.getOptional("reinforcement") /** - * The type of method. Is either `supervised` or `dpo`. + * Configuration for the supervised fine-tuning method. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun type(): Optional = type.getOptional("type") + fun supervised(): Optional = supervised.getOptional("supervised") + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type /** * Returns the raw JSON value of [dpo]. * * Unlike [dpo], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("dpo") @ExcludeMissing fun _dpo(): JsonField = dpo + @JsonProperty("dpo") @ExcludeMissing fun _dpo(): JsonField = dpo /** - * Returns the raw JSON value of [supervised]. + * Returns the raw JSON value of [reinforcement]. * - * Unlike [supervised], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [reinforcement], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("supervised") + @JsonProperty("reinforcement") @ExcludeMissing - fun _supervised(): JsonField = supervised + fun _reinforcement(): JsonField = reinforcement /** - * Returns the raw JSON value of [type]. + * Returns the raw JSON value of [supervised]. * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [supervised], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + @JsonProperty("supervised") + @ExcludeMissing + fun _supervised(): JsonField = supervised @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -2433,63 +2459,87 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Method]. */ + /** + * Returns a mutable builder for constructing an instance of [Method]. + * + * The following fields are required: + * ```java + * .type() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [Method]. */ class Builder internal constructor() { - private var dpo: JsonField = JsonMissing.of() - private var supervised: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null + private var dpo: JsonField = JsonMissing.of() + private var reinforcement: JsonField = JsonMissing.of() + private var supervised: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(method: Method) = apply { + type = method.type dpo = method.dpo + reinforcement = method.reinforcement supervised = method.supervised - type = method.type additionalProperties = method.additionalProperties.toMutableMap() } - /** Configuration for the DPO fine-tuning method. */ - fun dpo(dpo: Dpo) = dpo(JsonField.of(dpo)) + /** The type of method. Is either `supervised`, `dpo`, or `reinforcement`. */ + fun type(type: Type) = type(JsonField.of(type)) /** - * Sets [Builder.dpo] to an arbitrary JSON value. + * Sets [Builder.type] to an arbitrary JSON value. * - * You should usually call [Builder.dpo] with a well-typed [Dpo] value instead. This + * You should usually call [Builder.type] with a well-typed [Type] value instead. This * method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun dpo(dpo: JsonField) = apply { this.dpo = dpo } + fun type(type: JsonField) = apply { this.type = type } - /** Configuration for the supervised fine-tuning method. */ - fun supervised(supervised: Supervised) = supervised(JsonField.of(supervised)) + /** Configuration for the DPO fine-tuning method. */ + fun dpo(dpo: DpoMethod) = dpo(JsonField.of(dpo)) /** - * Sets [Builder.supervised] to an arbitrary JSON value. + * Sets [Builder.dpo] to an arbitrary JSON value. * - * You should usually call [Builder.supervised] with a well-typed [Supervised] value - * instead. This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.dpo] with a well-typed [DpoMethod] value instead. + * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun supervised(supervised: JsonField) = apply { - this.supervised = supervised + fun dpo(dpo: JsonField) = apply { this.dpo = dpo } + + /** Configuration for the reinforcement fine-tuning method. */ + fun reinforcement(reinforcement: ReinforcementMethod) = + reinforcement(JsonField.of(reinforcement)) + + /** + * Sets [Builder.reinforcement] to an arbitrary JSON value. + * + * You should usually call [Builder.reinforcement] with a well-typed + * [ReinforcementMethod] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun reinforcement(reinforcement: JsonField) = apply { + this.reinforcement = reinforcement } - /** The type of method. Is either `supervised` or `dpo`. */ - fun type(type: Type) = type(JsonField.of(type)) + /** Configuration for the supervised fine-tuning method. */ + fun supervised(supervised: SupervisedMethod) = supervised(JsonField.of(supervised)) /** - * Sets [Builder.type] to an arbitrary JSON value. + * Sets [Builder.supervised] to an arbitrary JSON value. * - * You should usually call [Builder.type] with a well-typed [Type] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.supervised] with a well-typed [SupervisedMethod] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. */ - fun type(type: JsonField) = apply { this.type = type } + fun supervised(supervised: JsonField) = apply { + this.supervised = supervised + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -2514,8 +2564,22 @@ private constructor( * Returns an immutable instance of [Method]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ - fun build(): Method = Method(dpo, supervised, type, additionalProperties.toMutableMap()) + fun build(): Method = + Method( + checkRequired("type", type), + dpo, + reinforcement, + supervised, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -2525,9 +2589,10 @@ private constructor( return@apply } + type().validate() dpo().ifPresent { it.validate() } + reinforcement().ifPresent { it.validate() } supervised().ifPresent { it.validate() } - type().ifPresent { it.validate() } validated = true } @@ -2547,2263 +2612,31 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (dpo.asKnown().getOrNull()?.validity() ?: 0) + - (supervised.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) + (type.asKnown().getOrNull()?.validity() ?: 0) + + (dpo.asKnown().getOrNull()?.validity() ?: 0) + + (reinforcement.asKnown().getOrNull()?.validity() ?: 0) + + (supervised.asKnown().getOrNull()?.validity() ?: 0) - /** Configuration for the DPO fine-tuning method. */ - class Dpo - private constructor( - private val hyperparameters: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("hyperparameters") - @ExcludeMissing - hyperparameters: JsonField = JsonMissing.of() - ) : this(hyperparameters, mutableMapOf()) - - /** - * The hyperparameters used for the fine-tuning job. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun hyperparameters(): Optional = - hyperparameters.getOptional("hyperparameters") + /** The type of method. Is either `supervised`, `dpo`, or `reinforcement`. */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { /** - * Returns the raw JSON value of [hyperparameters]. + * Returns this class instance's raw value. * - * Unlike [hyperparameters], this method doesn't throw if the JSON field has an - * unexpected type. + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. */ - @JsonProperty("hyperparameters") - @ExcludeMissing - fun _hyperparameters(): JsonField = hyperparameters - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value companion object { - /** Returns a mutable builder for constructing an instance of [Dpo]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Dpo]. */ - class Builder internal constructor() { - - private var hyperparameters: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(dpo: Dpo) = apply { - hyperparameters = dpo.hyperparameters - additionalProperties = dpo.additionalProperties.toMutableMap() - } - - /** The hyperparameters used for the fine-tuning job. */ - fun hyperparameters(hyperparameters: Hyperparameters) = - hyperparameters(JsonField.of(hyperparameters)) - - /** - * Sets [Builder.hyperparameters] to an arbitrary JSON value. - * - * You should usually call [Builder.hyperparameters] with a well-typed - * [Hyperparameters] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun hyperparameters(hyperparameters: JsonField) = apply { - this.hyperparameters = hyperparameters - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Dpo]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Dpo = Dpo(hyperparameters, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Dpo = apply { - if (validated) { - return@apply - } - - hyperparameters().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) - - /** The hyperparameters used for the fine-tuning job. */ - class Hyperparameters - private constructor( - private val batchSize: JsonField, - private val beta: JsonField, - private val learningRateMultiplier: JsonField, - private val nEpochs: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("batch_size") - @ExcludeMissing - batchSize: JsonField = JsonMissing.of(), - @JsonProperty("beta") @ExcludeMissing beta: JsonField = JsonMissing.of(), - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - learningRateMultiplier: JsonField = JsonMissing.of(), - @JsonProperty("n_epochs") - @ExcludeMissing - nEpochs: JsonField = JsonMissing.of(), - ) : this(batchSize, beta, learningRateMultiplier, nEpochs, mutableMapOf()) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun batchSize(): Optional = batchSize.getOptional("batch_size") - - /** - * The beta value for the DPO method. A higher beta value will increase the weight - * of the penalty between the policy and reference model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun beta(): Optional = beta.getOptional("beta") - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun learningRateMultiplier(): Optional = - learningRateMultiplier.getOptional("learning_rate_multiplier") - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") - - /** - * Returns the raw JSON value of [batchSize]. - * - * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("batch_size") - @ExcludeMissing - fun _batchSize(): JsonField = batchSize - - /** - * Returns the raw JSON value of [beta]. - * - * Unlike [beta], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("beta") @ExcludeMissing fun _beta(): JsonField = beta - - /** - * Returns the raw JSON value of [learningRateMultiplier]. - * - * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - fun _learningRateMultiplier(): JsonField = - learningRateMultiplier - - /** - * Returns the raw JSON value of [nEpochs]. - * - * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("n_epochs") - @ExcludeMissing - fun _nEpochs(): JsonField = nEpochs - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Hyperparameters]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Hyperparameters]. */ - class Builder internal constructor() { - - private var batchSize: JsonField = JsonMissing.of() - private var beta: JsonField = JsonMissing.of() - private var learningRateMultiplier: JsonField = - JsonMissing.of() - private var nEpochs: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(hyperparameters: Hyperparameters) = apply { - batchSize = hyperparameters.batchSize - beta = hyperparameters.beta - learningRateMultiplier = hyperparameters.learningRateMultiplier - nEpochs = hyperparameters.nEpochs - additionalProperties = hyperparameters.additionalProperties.toMutableMap() - } - - /** - * Number of examples in each batch. A larger batch size means that model - * parameters are updated less frequently, but with lower variance. - */ - fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) - - /** - * Sets [Builder.batchSize] to an arbitrary JSON value. - * - * You should usually call [Builder.batchSize] with a well-typed [BatchSize] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun batchSize(batchSize: JsonField) = apply { - this.batchSize = batchSize - } - - /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ - fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) - - /** Alias for calling [batchSize] with `BatchSize.ofManual(manual)`. */ - fun batchSize(manual: Long) = batchSize(BatchSize.ofManual(manual)) - - /** - * The beta value for the DPO method. A higher beta value will increase the - * weight of the penalty between the policy and reference model. - */ - fun beta(beta: Beta) = beta(JsonField.of(beta)) - - /** - * Sets [Builder.beta] to an arbitrary JSON value. - * - * You should usually call [Builder.beta] with a well-typed [Beta] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun beta(beta: JsonField) = apply { this.beta = beta } - - /** Alias for calling [beta] with `Beta.ofAuto()`. */ - fun betaAuto() = beta(Beta.ofAuto()) - - /** Alias for calling [beta] with `Beta.ofManual(manual)`. */ - fun beta(manual: Double) = beta(Beta.ofManual(manual)) - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful - * to avoid overfitting. - */ - fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = - learningRateMultiplier(JsonField.of(learningRateMultiplier)) - - /** - * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. - * - * You should usually call [Builder.learningRateMultiplier] with a well-typed - * [LearningRateMultiplier] value instead. This method is primarily for setting - * the field to an undocumented or not yet supported value. - */ - fun learningRateMultiplier( - learningRateMultiplier: JsonField - ) = apply { this.learningRateMultiplier = learningRateMultiplier } - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofAuto()`. - */ - fun learningRateMultiplierAuto() = - learningRateMultiplier(LearningRateMultiplier.ofAuto()) - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofManual(manual)`. - */ - fun learningRateMultiplier(manual: Double) = - learningRateMultiplier(LearningRateMultiplier.ofManual(manual)) - - /** - * The number of epochs to train the model for. An epoch refers to one full - * cycle through the training dataset. - */ - fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) - - /** - * Sets [Builder.nEpochs] to an arbitrary JSON value. - * - * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } - - /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ - fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) - - /** Alias for calling [nEpochs] with `NEpochs.ofManual(manual)`. */ - fun nEpochs(manual: Long) = nEpochs(NEpochs.ofManual(manual)) - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Hyperparameters]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Hyperparameters = - Hyperparameters( - batchSize, - beta, - learningRateMultiplier, - nEpochs, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Hyperparameters = apply { - if (validated) { - return@apply - } - - batchSize().ifPresent { it.validate() } - beta().ifPresent { it.validate() } - learningRateMultiplier().ifPresent { it.validate() } - nEpochs().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (batchSize.asKnown().getOrNull()?.validity() ?: 0) + - (beta.asKnown().getOrNull()?.validity() ?: 0) + - (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + - (nEpochs.asKnown().getOrNull()?.validity() ?: 0) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - */ - @JsonDeserialize(using = BatchSize.Deserializer::class) - @JsonSerialize(using = BatchSize.Serializer::class) - class BatchSize - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): BatchSize = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is BatchSize && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "BatchSize{auto=$auto}" - manual != null -> "BatchSize{manual=$manual}" - _json != null -> "BatchSize{_unknown=$_json}" - else -> throw IllegalStateException("Invalid BatchSize") - } - - companion object { - - @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = BatchSize(manual = manual) - } - - /** - * An interface that defines how to map each variant of [BatchSize] to a value - * of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [BatchSize] to a value of type [T]. - * - * An instance of [BatchSize] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown BatchSize: $json") - } - } - - internal class Deserializer : BaseDeserializer(BatchSize::class) { + @JvmField val SUPERVISED = of("supervised") - override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { - val json = JsonValue.fromJsonNode(node) + @JvmField val DPO = of("dpo") - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { BatchSize(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - BatchSize(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> BatchSize(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(BatchSize::class) { - - override fun serialize( - value: BatchSize, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid BatchSize") - } - } - } - } - - /** - * The beta value for the DPO method. A higher beta value will increase the weight - * of the penalty between the policy and reference model. - */ - @JsonDeserialize(using = Beta.Deserializer::class) - @JsonSerialize(using = Beta.Serializer::class) - class Beta - private constructor( - private val auto: JsonValue? = null, - private val manual: Double? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Double = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Beta = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Double) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Double) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Beta && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "Beta{auto=$auto}" - manual != null -> "Beta{manual=$manual}" - _json != null -> "Beta{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Beta") - } - - companion object { - - @JvmStatic fun ofAuto() = Beta(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Double) = Beta(manual = manual) - } - - /** - * An interface that defines how to map each variant of [Beta] to a value of - * type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Double): T - - /** - * Maps an unknown variant of [Beta] to a value of type [T]. - * - * An instance of [Beta] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Beta: $json") - } - } - - internal class Deserializer : BaseDeserializer(Beta::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Beta { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Beta(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - Beta(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> Beta(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Beta::class) { - - override fun serialize( - value: Beta, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Beta") - } - } - } - } - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - */ - @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) - @JsonSerialize(using = LearningRateMultiplier.Serializer::class) - class LearningRateMultiplier - private constructor( - private val auto: JsonValue? = null, - private val manual: Double? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Double = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): LearningRateMultiplier = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Double) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Double) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "LearningRateMultiplier{auto=$auto}" - manual != null -> "LearningRateMultiplier{manual=$manual}" - _json != null -> "LearningRateMultiplier{_unknown=$_json}" - else -> throw IllegalStateException("Invalid LearningRateMultiplier") - } - - companion object { - - @JvmStatic - fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) - - @JvmStatic - fun ofManual(manual: Double) = LearningRateMultiplier(manual = manual) - } - - /** - * An interface that defines how to map each variant of [LearningRateMultiplier] - * to a value of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Double): T - - /** - * Maps an unknown variant of [LearningRateMultiplier] to a value of type - * [T]. - * - * An instance of [LearningRateMultiplier] can contain an unknown variant if - * it was deserialized from data that doesn't match any known variant. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException( - "Unknown LearningRateMultiplier: $json" - ) - } - } - - internal class Deserializer : - BaseDeserializer(LearningRateMultiplier::class) { - - override fun ObjectCodec.deserialize( - node: JsonNode - ): LearningRateMultiplier { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { - LearningRateMultiplier(auto = it, _json = json) - } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - LearningRateMultiplier(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> LearningRateMultiplier(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : - BaseSerializer(LearningRateMultiplier::class) { - - override fun serialize( - value: LearningRateMultiplier, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> - throw IllegalStateException("Invalid LearningRateMultiplier") - } - } - } - } - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - */ - @JsonDeserialize(using = NEpochs.Deserializer::class) - @JsonSerialize(using = NEpochs.Serializer::class) - class NEpochs - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): NEpochs = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is NEpochs && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "NEpochs{auto=$auto}" - manual != null -> "NEpochs{manual=$manual}" - _json != null -> "NEpochs{_unknown=$_json}" - else -> throw IllegalStateException("Invalid NEpochs") - } - - companion object { - - @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = NEpochs(manual = manual) - } - - /** - * An interface that defines how to map each variant of [NEpochs] to a value of - * type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [NEpochs] to a value of type [T]. - * - * An instance of [NEpochs] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown NEpochs: $json") - } - } - - internal class Deserializer : BaseDeserializer(NEpochs::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { NEpochs(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - NEpochs(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> NEpochs(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(NEpochs::class) { - - override fun serialize( - value: NEpochs, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid NEpochs") - } - } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Hyperparameters && batchSize == other.batchSize && beta == other.beta && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(batchSize, beta, learningRateMultiplier, nEpochs, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Hyperparameters{batchSize=$batchSize, beta=$beta, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Dpo && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(hyperparameters, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Dpo{hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" - } - - /** Configuration for the supervised fine-tuning method. */ - class Supervised - private constructor( - private val hyperparameters: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("hyperparameters") - @ExcludeMissing - hyperparameters: JsonField = JsonMissing.of() - ) : this(hyperparameters, mutableMapOf()) - - /** - * The hyperparameters used for the fine-tuning job. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun hyperparameters(): Optional = - hyperparameters.getOptional("hyperparameters") - - /** - * Returns the raw JSON value of [hyperparameters]. - * - * Unlike [hyperparameters], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("hyperparameters") - @ExcludeMissing - fun _hyperparameters(): JsonField = hyperparameters - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Supervised]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Supervised]. */ - class Builder internal constructor() { - - private var hyperparameters: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(supervised: Supervised) = apply { - hyperparameters = supervised.hyperparameters - additionalProperties = supervised.additionalProperties.toMutableMap() - } - - /** The hyperparameters used for the fine-tuning job. */ - fun hyperparameters(hyperparameters: Hyperparameters) = - hyperparameters(JsonField.of(hyperparameters)) - - /** - * Sets [Builder.hyperparameters] to an arbitrary JSON value. - * - * You should usually call [Builder.hyperparameters] with a well-typed - * [Hyperparameters] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun hyperparameters(hyperparameters: JsonField) = apply { - this.hyperparameters = hyperparameters - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Supervised]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Supervised = - Supervised(hyperparameters, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Supervised = apply { - if (validated) { - return@apply - } - - hyperparameters().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) - - /** The hyperparameters used for the fine-tuning job. */ - class Hyperparameters - private constructor( - private val batchSize: JsonField, - private val learningRateMultiplier: JsonField, - private val nEpochs: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("batch_size") - @ExcludeMissing - batchSize: JsonField = JsonMissing.of(), - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - learningRateMultiplier: JsonField = JsonMissing.of(), - @JsonProperty("n_epochs") - @ExcludeMissing - nEpochs: JsonField = JsonMissing.of(), - ) : this(batchSize, learningRateMultiplier, nEpochs, mutableMapOf()) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun batchSize(): Optional = batchSize.getOptional("batch_size") - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun learningRateMultiplier(): Optional = - learningRateMultiplier.getOptional("learning_rate_multiplier") - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") - - /** - * Returns the raw JSON value of [batchSize]. - * - * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("batch_size") - @ExcludeMissing - fun _batchSize(): JsonField = batchSize - - /** - * Returns the raw JSON value of [learningRateMultiplier]. - * - * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - fun _learningRateMultiplier(): JsonField = - learningRateMultiplier - - /** - * Returns the raw JSON value of [nEpochs]. - * - * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("n_epochs") - @ExcludeMissing - fun _nEpochs(): JsonField = nEpochs - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Hyperparameters]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Hyperparameters]. */ - class Builder internal constructor() { - - private var batchSize: JsonField = JsonMissing.of() - private var learningRateMultiplier: JsonField = - JsonMissing.of() - private var nEpochs: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(hyperparameters: Hyperparameters) = apply { - batchSize = hyperparameters.batchSize - learningRateMultiplier = hyperparameters.learningRateMultiplier - nEpochs = hyperparameters.nEpochs - additionalProperties = hyperparameters.additionalProperties.toMutableMap() - } - - /** - * Number of examples in each batch. A larger batch size means that model - * parameters are updated less frequently, but with lower variance. - */ - fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) - - /** - * Sets [Builder.batchSize] to an arbitrary JSON value. - * - * You should usually call [Builder.batchSize] with a well-typed [BatchSize] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun batchSize(batchSize: JsonField) = apply { - this.batchSize = batchSize - } - - /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ - fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) - - /** Alias for calling [batchSize] with `BatchSize.ofManual(manual)`. */ - fun batchSize(manual: Long) = batchSize(BatchSize.ofManual(manual)) - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful - * to avoid overfitting. - */ - fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = - learningRateMultiplier(JsonField.of(learningRateMultiplier)) - - /** - * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. - * - * You should usually call [Builder.learningRateMultiplier] with a well-typed - * [LearningRateMultiplier] value instead. This method is primarily for setting - * the field to an undocumented or not yet supported value. - */ - fun learningRateMultiplier( - learningRateMultiplier: JsonField - ) = apply { this.learningRateMultiplier = learningRateMultiplier } - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofAuto()`. - */ - fun learningRateMultiplierAuto() = - learningRateMultiplier(LearningRateMultiplier.ofAuto()) - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofManual(manual)`. - */ - fun learningRateMultiplier(manual: Double) = - learningRateMultiplier(LearningRateMultiplier.ofManual(manual)) - - /** - * The number of epochs to train the model for. An epoch refers to one full - * cycle through the training dataset. - */ - fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) - - /** - * Sets [Builder.nEpochs] to an arbitrary JSON value. - * - * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } - - /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ - fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) - - /** Alias for calling [nEpochs] with `NEpochs.ofManual(manual)`. */ - fun nEpochs(manual: Long) = nEpochs(NEpochs.ofManual(manual)) - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Hyperparameters]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Hyperparameters = - Hyperparameters( - batchSize, - learningRateMultiplier, - nEpochs, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Hyperparameters = apply { - if (validated) { - return@apply - } - - batchSize().ifPresent { it.validate() } - learningRateMultiplier().ifPresent { it.validate() } - nEpochs().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (batchSize.asKnown().getOrNull()?.validity() ?: 0) + - (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + - (nEpochs.asKnown().getOrNull()?.validity() ?: 0) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - */ - @JsonDeserialize(using = BatchSize.Deserializer::class) - @JsonSerialize(using = BatchSize.Serializer::class) - class BatchSize - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): BatchSize = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is BatchSize && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "BatchSize{auto=$auto}" - manual != null -> "BatchSize{manual=$manual}" - _json != null -> "BatchSize{_unknown=$_json}" - else -> throw IllegalStateException("Invalid BatchSize") - } - - companion object { - - @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = BatchSize(manual = manual) - } - - /** - * An interface that defines how to map each variant of [BatchSize] to a value - * of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [BatchSize] to a value of type [T]. - * - * An instance of [BatchSize] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown BatchSize: $json") - } - } - - internal class Deserializer : BaseDeserializer(BatchSize::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { BatchSize(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - BatchSize(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> BatchSize(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(BatchSize::class) { - - override fun serialize( - value: BatchSize, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid BatchSize") - } - } - } - } - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - */ - @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) - @JsonSerialize(using = LearningRateMultiplier.Serializer::class) - class LearningRateMultiplier - private constructor( - private val auto: JsonValue? = null, - private val manual: Double? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Double = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): LearningRateMultiplier = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Double) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Double) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "LearningRateMultiplier{auto=$auto}" - manual != null -> "LearningRateMultiplier{manual=$manual}" - _json != null -> "LearningRateMultiplier{_unknown=$_json}" - else -> throw IllegalStateException("Invalid LearningRateMultiplier") - } - - companion object { - - @JvmStatic - fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) - - @JvmStatic - fun ofManual(manual: Double) = LearningRateMultiplier(manual = manual) - } - - /** - * An interface that defines how to map each variant of [LearningRateMultiplier] - * to a value of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Double): T - - /** - * Maps an unknown variant of [LearningRateMultiplier] to a value of type - * [T]. - * - * An instance of [LearningRateMultiplier] can contain an unknown variant if - * it was deserialized from data that doesn't match any known variant. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException( - "Unknown LearningRateMultiplier: $json" - ) - } - } - - internal class Deserializer : - BaseDeserializer(LearningRateMultiplier::class) { - - override fun ObjectCodec.deserialize( - node: JsonNode - ): LearningRateMultiplier { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { - LearningRateMultiplier(auto = it, _json = json) - } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - LearningRateMultiplier(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> LearningRateMultiplier(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : - BaseSerializer(LearningRateMultiplier::class) { - - override fun serialize( - value: LearningRateMultiplier, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> - throw IllegalStateException("Invalid LearningRateMultiplier") - } - } - } - } - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - */ - @JsonDeserialize(using = NEpochs.Deserializer::class) - @JsonSerialize(using = NEpochs.Serializer::class) - class NEpochs - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): NEpochs = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is NEpochs && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "NEpochs{auto=$auto}" - manual != null -> "NEpochs{manual=$manual}" - _json != null -> "NEpochs{_unknown=$_json}" - else -> throw IllegalStateException("Invalid NEpochs") - } - - companion object { - - @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = NEpochs(manual = manual) - } - - /** - * An interface that defines how to map each variant of [NEpochs] to a value of - * type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [NEpochs] to a value of type [T]. - * - * An instance of [NEpochs] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown NEpochs: $json") - } - } - - internal class Deserializer : BaseDeserializer(NEpochs::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { NEpochs(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - NEpochs(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> NEpochs(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(NEpochs::class) { - - override fun serialize( - value: NEpochs, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid NEpochs") - } - } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Hyperparameters && batchSize == other.batchSize && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(batchSize, learningRateMultiplier, nEpochs, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Hyperparameters{batchSize=$batchSize, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Supervised && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(hyperparameters, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Supervised{hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" - } - - /** The type of method. Is either `supervised` or `dpo`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val SUPERVISED = of("supervised") - - @JvmField val DPO = of("dpo") + @JvmField val REINFORCEMENT = of("reinforcement") @JvmStatic fun of(value: String) = Type(JsonField.of(value)) } @@ -4812,6 +2645,7 @@ private constructor( enum class Known { SUPERVISED, DPO, + REINFORCEMENT, } /** @@ -4826,6 +2660,7 @@ private constructor( enum class Value { SUPERVISED, DPO, + REINFORCEMENT, /** An enum member indicating that [Type] was instantiated with an unknown value. */ _UNKNOWN, } @@ -4841,6 +2676,7 @@ private constructor( when (this) { SUPERVISED -> Value.SUPERVISED DPO -> Value.DPO + REINFORCEMENT -> Value.REINFORCEMENT else -> Value._UNKNOWN } @@ -4857,6 +2693,7 @@ private constructor( when (this) { SUPERVISED -> Known.SUPERVISED DPO -> Known.DPO + REINFORCEMENT -> Known.REINFORCEMENT else -> throw OpenAIInvalidDataException("Unknown Type: $value") } @@ -4919,17 +2756,17 @@ private constructor( return true } - return /* spotless:off */ other is Method && dpo == other.dpo && supervised == other.supervised && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Method && type == other.type && dpo == other.dpo && reinforcement == other.reinforcement && supervised == other.supervised && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(dpo, supervised, type, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(type, dpo, reinforcement, supervised, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Method{dpo=$dpo, supervised=$supervised, type=$type, additionalProperties=$additionalProperties}" + "Method{type=$type, dpo=$dpo, reinforcement=$reinforcement, supervised=$supervised, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCancelParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCancelParams.kt index 4d7c9f96c..a4fbd422f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCancelParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCancelParams.kt @@ -4,23 +4,23 @@ package com.openai.models.finetuning.jobs import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Immediately cancel a fine-tune job. */ class JobCancelParams private constructor( - private val fineTuningJobId: String, + private val fineTuningJobId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun fineTuningJobId(): String = fineTuningJobId + fun fineTuningJobId(): Optional = Optional.ofNullable(fineTuningJobId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [JobCancelParams]. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - */ + @JvmStatic fun none(): JobCancelParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [JobCancelParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,10 +54,14 @@ private constructor( additionalBodyProperties = jobCancelParams.additionalBodyProperties.toMutableMap() } - fun fineTuningJobId(fineTuningJobId: String) = apply { + fun fineTuningJobId(fineTuningJobId: String?) = apply { this.fineTuningJobId = fineTuningJobId } + /** Alias for calling [Builder.fineTuningJobId] with `fineTuningJobId.orElse(null)`. */ + fun fineTuningJobId(fineTuningJobId: Optional) = + fineTuningJobId(fineTuningJobId.getOrNull()) + fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() putAllAdditionalHeaders(additionalHeaders) @@ -187,17 +186,10 @@ private constructor( * Returns an immutable instance of [JobCancelParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): JobCancelParams = JobCancelParams( - checkRequired("fineTuningJobId", fineTuningJobId), + fineTuningJobId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -209,7 +201,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fineTuningJobId + 0 -> fineTuningJobId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCreateParams.kt index 345624c28..f08fe5de7 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobCreateParams.kt @@ -29,6 +29,9 @@ import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedMethod import java.util.Collections import java.util.Objects import java.util.Optional @@ -2835,20 +2838,32 @@ private constructor( /** The method used for fine-tuning. */ class Method private constructor( - private val dpo: JsonField, - private val supervised: JsonField, private val type: JsonField, + private val dpo: JsonField, + private val reinforcement: JsonField, + private val supervised: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( - @JsonProperty("dpo") @ExcludeMissing dpo: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + @JsonProperty("dpo") @ExcludeMissing dpo: JsonField = JsonMissing.of(), + @JsonProperty("reinforcement") + @ExcludeMissing + reinforcement: JsonField = JsonMissing.of(), @JsonProperty("supervised") @ExcludeMissing - supervised: JsonField = JsonMissing.of(), - @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), - ) : this(dpo, supervised, type, mutableMapOf()) + supervised: JsonField = JsonMissing.of(), + ) : this(type, dpo, reinforcement, supervised, mutableMapOf()) + + /** + * The type of method. Is either `supervised`, `dpo`, or `reinforcement`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun type(): Type = type.getRequired("type") /** * Configuration for the DPO fine-tuning method. @@ -2856,46 +2871,57 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun dpo(): Optional = dpo.getOptional("dpo") + fun dpo(): Optional = dpo.getOptional("dpo") /** - * Configuration for the supervised fine-tuning method. + * Configuration for the reinforcement fine-tuning method. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun supervised(): Optional = supervised.getOptional("supervised") + fun reinforcement(): Optional = + reinforcement.getOptional("reinforcement") /** - * The type of method. Is either `supervised` or `dpo`. + * Configuration for the supervised fine-tuning method. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun type(): Optional = type.getOptional("type") + fun supervised(): Optional = supervised.getOptional("supervised") + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type /** * Returns the raw JSON value of [dpo]. * * Unlike [dpo], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("dpo") @ExcludeMissing fun _dpo(): JsonField = dpo + @JsonProperty("dpo") @ExcludeMissing fun _dpo(): JsonField = dpo /** - * Returns the raw JSON value of [supervised]. + * Returns the raw JSON value of [reinforcement]. * - * Unlike [supervised], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [reinforcement], this method doesn't throw if the JSON field has an unexpected + * type. */ - @JsonProperty("supervised") + @JsonProperty("reinforcement") @ExcludeMissing - fun _supervised(): JsonField = supervised + fun _reinforcement(): JsonField = reinforcement /** - * Returns the raw JSON value of [type]. + * Returns the raw JSON value of [supervised]. * - * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [supervised], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + @JsonProperty("supervised") + @ExcludeMissing + fun _supervised(): JsonField = supervised @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -2911,63 +2937,87 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Method]. */ + /** + * Returns a mutable builder for constructing an instance of [Method]. + * + * The following fields are required: + * ```java + * .type() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [Method]. */ class Builder internal constructor() { - private var dpo: JsonField = JsonMissing.of() - private var supervised: JsonField = JsonMissing.of() - private var type: JsonField = JsonMissing.of() + private var type: JsonField? = null + private var dpo: JsonField = JsonMissing.of() + private var reinforcement: JsonField = JsonMissing.of() + private var supervised: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(method: Method) = apply { + type = method.type dpo = method.dpo + reinforcement = method.reinforcement supervised = method.supervised - type = method.type additionalProperties = method.additionalProperties.toMutableMap() } - /** Configuration for the DPO fine-tuning method. */ - fun dpo(dpo: Dpo) = dpo(JsonField.of(dpo)) + /** The type of method. Is either `supervised`, `dpo`, or `reinforcement`. */ + fun type(type: Type) = type(JsonField.of(type)) /** - * Sets [Builder.dpo] to an arbitrary JSON value. + * Sets [Builder.type] to an arbitrary JSON value. * - * You should usually call [Builder.dpo] with a well-typed [Dpo] value instead. This + * You should usually call [Builder.type] with a well-typed [Type] value instead. This * method is primarily for setting the field to an undocumented or not yet supported * value. */ - fun dpo(dpo: JsonField) = apply { this.dpo = dpo } + fun type(type: JsonField) = apply { this.type = type } - /** Configuration for the supervised fine-tuning method. */ - fun supervised(supervised: Supervised) = supervised(JsonField.of(supervised)) + /** Configuration for the DPO fine-tuning method. */ + fun dpo(dpo: DpoMethod) = dpo(JsonField.of(dpo)) /** - * Sets [Builder.supervised] to an arbitrary JSON value. + * Sets [Builder.dpo] to an arbitrary JSON value. * - * You should usually call [Builder.supervised] with a well-typed [Supervised] value - * instead. This method is primarily for setting the field to an undocumented or not yet + * You should usually call [Builder.dpo] with a well-typed [DpoMethod] value instead. + * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun supervised(supervised: JsonField) = apply { - this.supervised = supervised + fun dpo(dpo: JsonField) = apply { this.dpo = dpo } + + /** Configuration for the reinforcement fine-tuning method. */ + fun reinforcement(reinforcement: ReinforcementMethod) = + reinforcement(JsonField.of(reinforcement)) + + /** + * Sets [Builder.reinforcement] to an arbitrary JSON value. + * + * You should usually call [Builder.reinforcement] with a well-typed + * [ReinforcementMethod] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun reinforcement(reinforcement: JsonField) = apply { + this.reinforcement = reinforcement } - /** The type of method. Is either `supervised` or `dpo`. */ - fun type(type: Type) = type(JsonField.of(type)) + /** Configuration for the supervised fine-tuning method. */ + fun supervised(supervised: SupervisedMethod) = supervised(JsonField.of(supervised)) /** - * Sets [Builder.type] to an arbitrary JSON value. + * Sets [Builder.supervised] to an arbitrary JSON value. * - * You should usually call [Builder.type] with a well-typed [Type] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.supervised] with a well-typed [SupervisedMethod] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. */ - fun type(type: JsonField) = apply { this.type = type } + fun supervised(supervised: JsonField) = apply { + this.supervised = supervised + } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -2992,8 +3042,22 @@ private constructor( * Returns an immutable instance of [Method]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .type() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ - fun build(): Method = Method(dpo, supervised, type, additionalProperties.toMutableMap()) + fun build(): Method = + Method( + checkRequired("type", type), + dpo, + reinforcement, + supervised, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -3003,9 +3067,10 @@ private constructor( return@apply } + type().validate() dpo().ifPresent { it.validate() } + reinforcement().ifPresent { it.validate() } supervised().ifPresent { it.validate() } - type().ifPresent { it.validate() } validated = true } @@ -3025,2263 +3090,31 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (dpo.asKnown().getOrNull()?.validity() ?: 0) + - (supervised.asKnown().getOrNull()?.validity() ?: 0) + - (type.asKnown().getOrNull()?.validity() ?: 0) - - /** Configuration for the DPO fine-tuning method. */ - class Dpo - private constructor( - private val hyperparameters: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("hyperparameters") - @ExcludeMissing - hyperparameters: JsonField = JsonMissing.of() - ) : this(hyperparameters, mutableMapOf()) + (type.asKnown().getOrNull()?.validity() ?: 0) + + (dpo.asKnown().getOrNull()?.validity() ?: 0) + + (reinforcement.asKnown().getOrNull()?.validity() ?: 0) + + (supervised.asKnown().getOrNull()?.validity() ?: 0) - /** - * The hyperparameters used for the fine-tuning job. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun hyperparameters(): Optional = - hyperparameters.getOptional("hyperparameters") + /** The type of method. Is either `supervised`, `dpo`, or `reinforcement`. */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { /** - * Returns the raw JSON value of [hyperparameters]. + * Returns this class instance's raw value. * - * Unlike [hyperparameters], this method doesn't throw if the JSON field has an - * unexpected type. + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. */ - @JsonProperty("hyperparameters") - @ExcludeMissing - fun _hyperparameters(): JsonField = hyperparameters - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value companion object { - /** Returns a mutable builder for constructing an instance of [Dpo]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Dpo]. */ - class Builder internal constructor() { - - private var hyperparameters: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(dpo: Dpo) = apply { - hyperparameters = dpo.hyperparameters - additionalProperties = dpo.additionalProperties.toMutableMap() - } - - /** The hyperparameters used for the fine-tuning job. */ - fun hyperparameters(hyperparameters: Hyperparameters) = - hyperparameters(JsonField.of(hyperparameters)) - - /** - * Sets [Builder.hyperparameters] to an arbitrary JSON value. - * - * You should usually call [Builder.hyperparameters] with a well-typed - * [Hyperparameters] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun hyperparameters(hyperparameters: JsonField) = apply { - this.hyperparameters = hyperparameters - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Dpo]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Dpo = Dpo(hyperparameters, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Dpo = apply { - if (validated) { - return@apply - } - - hyperparameters().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) - - /** The hyperparameters used for the fine-tuning job. */ - class Hyperparameters - private constructor( - private val batchSize: JsonField, - private val beta: JsonField, - private val learningRateMultiplier: JsonField, - private val nEpochs: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("batch_size") - @ExcludeMissing - batchSize: JsonField = JsonMissing.of(), - @JsonProperty("beta") @ExcludeMissing beta: JsonField = JsonMissing.of(), - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - learningRateMultiplier: JsonField = JsonMissing.of(), - @JsonProperty("n_epochs") - @ExcludeMissing - nEpochs: JsonField = JsonMissing.of(), - ) : this(batchSize, beta, learningRateMultiplier, nEpochs, mutableMapOf()) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun batchSize(): Optional = batchSize.getOptional("batch_size") - - /** - * The beta value for the DPO method. A higher beta value will increase the weight - * of the penalty between the policy and reference model. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun beta(): Optional = beta.getOptional("beta") - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun learningRateMultiplier(): Optional = - learningRateMultiplier.getOptional("learning_rate_multiplier") - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") - - /** - * Returns the raw JSON value of [batchSize]. - * - * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("batch_size") - @ExcludeMissing - fun _batchSize(): JsonField = batchSize - - /** - * Returns the raw JSON value of [beta]. - * - * Unlike [beta], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("beta") @ExcludeMissing fun _beta(): JsonField = beta - - /** - * Returns the raw JSON value of [learningRateMultiplier]. - * - * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - fun _learningRateMultiplier(): JsonField = - learningRateMultiplier - - /** - * Returns the raw JSON value of [nEpochs]. - * - * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("n_epochs") - @ExcludeMissing - fun _nEpochs(): JsonField = nEpochs - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Hyperparameters]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Hyperparameters]. */ - class Builder internal constructor() { - - private var batchSize: JsonField = JsonMissing.of() - private var beta: JsonField = JsonMissing.of() - private var learningRateMultiplier: JsonField = - JsonMissing.of() - private var nEpochs: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(hyperparameters: Hyperparameters) = apply { - batchSize = hyperparameters.batchSize - beta = hyperparameters.beta - learningRateMultiplier = hyperparameters.learningRateMultiplier - nEpochs = hyperparameters.nEpochs - additionalProperties = hyperparameters.additionalProperties.toMutableMap() - } - - /** - * Number of examples in each batch. A larger batch size means that model - * parameters are updated less frequently, but with lower variance. - */ - fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) - - /** - * Sets [Builder.batchSize] to an arbitrary JSON value. - * - * You should usually call [Builder.batchSize] with a well-typed [BatchSize] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun batchSize(batchSize: JsonField) = apply { - this.batchSize = batchSize - } - - /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ - fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) - - /** Alias for calling [batchSize] with `BatchSize.ofManual(manual)`. */ - fun batchSize(manual: Long) = batchSize(BatchSize.ofManual(manual)) - - /** - * The beta value for the DPO method. A higher beta value will increase the - * weight of the penalty between the policy and reference model. - */ - fun beta(beta: Beta) = beta(JsonField.of(beta)) - - /** - * Sets [Builder.beta] to an arbitrary JSON value. - * - * You should usually call [Builder.beta] with a well-typed [Beta] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun beta(beta: JsonField) = apply { this.beta = beta } - - /** Alias for calling [beta] with `Beta.ofAuto()`. */ - fun betaAuto() = beta(Beta.ofAuto()) - - /** Alias for calling [beta] with `Beta.ofManual(manual)`. */ - fun beta(manual: Double) = beta(Beta.ofManual(manual)) - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful - * to avoid overfitting. - */ - fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = - learningRateMultiplier(JsonField.of(learningRateMultiplier)) - - /** - * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. - * - * You should usually call [Builder.learningRateMultiplier] with a well-typed - * [LearningRateMultiplier] value instead. This method is primarily for setting - * the field to an undocumented or not yet supported value. - */ - fun learningRateMultiplier( - learningRateMultiplier: JsonField - ) = apply { this.learningRateMultiplier = learningRateMultiplier } - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofAuto()`. - */ - fun learningRateMultiplierAuto() = - learningRateMultiplier(LearningRateMultiplier.ofAuto()) - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofManual(manual)`. - */ - fun learningRateMultiplier(manual: Double) = - learningRateMultiplier(LearningRateMultiplier.ofManual(manual)) - - /** - * The number of epochs to train the model for. An epoch refers to one full - * cycle through the training dataset. - */ - fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) - - /** - * Sets [Builder.nEpochs] to an arbitrary JSON value. - * - * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } - - /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ - fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) - - /** Alias for calling [nEpochs] with `NEpochs.ofManual(manual)`. */ - fun nEpochs(manual: Long) = nEpochs(NEpochs.ofManual(manual)) - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Hyperparameters]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Hyperparameters = - Hyperparameters( - batchSize, - beta, - learningRateMultiplier, - nEpochs, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Hyperparameters = apply { - if (validated) { - return@apply - } - - batchSize().ifPresent { it.validate() } - beta().ifPresent { it.validate() } - learningRateMultiplier().ifPresent { it.validate() } - nEpochs().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (batchSize.asKnown().getOrNull()?.validity() ?: 0) + - (beta.asKnown().getOrNull()?.validity() ?: 0) + - (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + - (nEpochs.asKnown().getOrNull()?.validity() ?: 0) + @JvmField val SUPERVISED = of("supervised") - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - */ - @JsonDeserialize(using = BatchSize.Deserializer::class) - @JsonSerialize(using = BatchSize.Serializer::class) - class BatchSize - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { + @JvmField val DPO = of("dpo") - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): BatchSize = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is BatchSize && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "BatchSize{auto=$auto}" - manual != null -> "BatchSize{manual=$manual}" - _json != null -> "BatchSize{_unknown=$_json}" - else -> throw IllegalStateException("Invalid BatchSize") - } - - companion object { - - @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = BatchSize(manual = manual) - } - - /** - * An interface that defines how to map each variant of [BatchSize] to a value - * of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [BatchSize] to a value of type [T]. - * - * An instance of [BatchSize] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown BatchSize: $json") - } - } - - internal class Deserializer : BaseDeserializer(BatchSize::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { BatchSize(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - BatchSize(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> BatchSize(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(BatchSize::class) { - - override fun serialize( - value: BatchSize, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid BatchSize") - } - } - } - } - - /** - * The beta value for the DPO method. A higher beta value will increase the weight - * of the penalty between the policy and reference model. - */ - @JsonDeserialize(using = Beta.Deserializer::class) - @JsonSerialize(using = Beta.Serializer::class) - class Beta - private constructor( - private val auto: JsonValue? = null, - private val manual: Double? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Double = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): Beta = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Double) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Double) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Beta && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "Beta{auto=$auto}" - manual != null -> "Beta{manual=$manual}" - _json != null -> "Beta{_unknown=$_json}" - else -> throw IllegalStateException("Invalid Beta") - } - - companion object { - - @JvmStatic fun ofAuto() = Beta(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Double) = Beta(manual = manual) - } - - /** - * An interface that defines how to map each variant of [Beta] to a value of - * type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Double): T - - /** - * Maps an unknown variant of [Beta] to a value of type [T]. - * - * An instance of [Beta] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown Beta: $json") - } - } - - internal class Deserializer : BaseDeserializer(Beta::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): Beta { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { Beta(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - Beta(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> Beta(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(Beta::class) { - - override fun serialize( - value: Beta, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid Beta") - } - } - } - } - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - */ - @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) - @JsonSerialize(using = LearningRateMultiplier.Serializer::class) - class LearningRateMultiplier - private constructor( - private val auto: JsonValue? = null, - private val manual: Double? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Double = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): LearningRateMultiplier = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Double) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Double) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "LearningRateMultiplier{auto=$auto}" - manual != null -> "LearningRateMultiplier{manual=$manual}" - _json != null -> "LearningRateMultiplier{_unknown=$_json}" - else -> throw IllegalStateException("Invalid LearningRateMultiplier") - } - - companion object { - - @JvmStatic - fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) - - @JvmStatic - fun ofManual(manual: Double) = LearningRateMultiplier(manual = manual) - } - - /** - * An interface that defines how to map each variant of [LearningRateMultiplier] - * to a value of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Double): T - - /** - * Maps an unknown variant of [LearningRateMultiplier] to a value of type - * [T]. - * - * An instance of [LearningRateMultiplier] can contain an unknown variant if - * it was deserialized from data that doesn't match any known variant. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException( - "Unknown LearningRateMultiplier: $json" - ) - } - } - - internal class Deserializer : - BaseDeserializer(LearningRateMultiplier::class) { - - override fun ObjectCodec.deserialize( - node: JsonNode - ): LearningRateMultiplier { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { - LearningRateMultiplier(auto = it, _json = json) - } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - LearningRateMultiplier(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> LearningRateMultiplier(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : - BaseSerializer(LearningRateMultiplier::class) { - - override fun serialize( - value: LearningRateMultiplier, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> - throw IllegalStateException("Invalid LearningRateMultiplier") - } - } - } - } - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - */ - @JsonDeserialize(using = NEpochs.Deserializer::class) - @JsonSerialize(using = NEpochs.Serializer::class) - class NEpochs - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): NEpochs = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is NEpochs && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "NEpochs{auto=$auto}" - manual != null -> "NEpochs{manual=$manual}" - _json != null -> "NEpochs{_unknown=$_json}" - else -> throw IllegalStateException("Invalid NEpochs") - } - - companion object { - - @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = NEpochs(manual = manual) - } - - /** - * An interface that defines how to map each variant of [NEpochs] to a value of - * type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [NEpochs] to a value of type [T]. - * - * An instance of [NEpochs] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown NEpochs: $json") - } - } - - internal class Deserializer : BaseDeserializer(NEpochs::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { NEpochs(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - NEpochs(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> NEpochs(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(NEpochs::class) { - - override fun serialize( - value: NEpochs, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid NEpochs") - } - } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Hyperparameters && batchSize == other.batchSize && beta == other.beta && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(batchSize, beta, learningRateMultiplier, nEpochs, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Hyperparameters{batchSize=$batchSize, beta=$beta, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Dpo && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(hyperparameters, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Dpo{hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" - } - - /** Configuration for the supervised fine-tuning method. */ - class Supervised - private constructor( - private val hyperparameters: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("hyperparameters") - @ExcludeMissing - hyperparameters: JsonField = JsonMissing.of() - ) : this(hyperparameters, mutableMapOf()) - - /** - * The hyperparameters used for the fine-tuning job. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). - */ - fun hyperparameters(): Optional = - hyperparameters.getOptional("hyperparameters") - - /** - * Returns the raw JSON value of [hyperparameters]. - * - * Unlike [hyperparameters], this method doesn't throw if the JSON field has an - * unexpected type. - */ - @JsonProperty("hyperparameters") - @ExcludeMissing - fun _hyperparameters(): JsonField = hyperparameters - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** Returns a mutable builder for constructing an instance of [Supervised]. */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Supervised]. */ - class Builder internal constructor() { - - private var hyperparameters: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(supervised: Supervised) = apply { - hyperparameters = supervised.hyperparameters - additionalProperties = supervised.additionalProperties.toMutableMap() - } - - /** The hyperparameters used for the fine-tuning job. */ - fun hyperparameters(hyperparameters: Hyperparameters) = - hyperparameters(JsonField.of(hyperparameters)) - - /** - * Sets [Builder.hyperparameters] to an arbitrary JSON value. - * - * You should usually call [Builder.hyperparameters] with a well-typed - * [Hyperparameters] value instead. This method is primarily for setting the field - * to an undocumented or not yet supported value. - */ - fun hyperparameters(hyperparameters: JsonField) = apply { - this.hyperparameters = hyperparameters - } - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Supervised]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Supervised = - Supervised(hyperparameters, additionalProperties.toMutableMap()) - } - - private var validated: Boolean = false - - fun validate(): Supervised = apply { - if (validated) { - return@apply - } - - hyperparameters().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) - - /** The hyperparameters used for the fine-tuning job. */ - class Hyperparameters - private constructor( - private val batchSize: JsonField, - private val learningRateMultiplier: JsonField, - private val nEpochs: JsonField, - private val additionalProperties: MutableMap, - ) { - - @JsonCreator - private constructor( - @JsonProperty("batch_size") - @ExcludeMissing - batchSize: JsonField = JsonMissing.of(), - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - learningRateMultiplier: JsonField = JsonMissing.of(), - @JsonProperty("n_epochs") - @ExcludeMissing - nEpochs: JsonField = JsonMissing.of(), - ) : this(batchSize, learningRateMultiplier, nEpochs, mutableMapOf()) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun batchSize(): Optional = batchSize.getOptional("batch_size") - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun learningRateMultiplier(): Optional = - learningRateMultiplier.getOptional("learning_rate_multiplier") - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. - * if the server responded with an unexpected value). - */ - fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") - - /** - * Returns the raw JSON value of [batchSize]. - * - * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("batch_size") - @ExcludeMissing - fun _batchSize(): JsonField = batchSize - - /** - * Returns the raw JSON value of [learningRateMultiplier]. - * - * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has - * an unexpected type. - */ - @JsonProperty("learning_rate_multiplier") - @ExcludeMissing - fun _learningRateMultiplier(): JsonField = - learningRateMultiplier - - /** - * Returns the raw JSON value of [nEpochs]. - * - * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("n_epochs") - @ExcludeMissing - fun _nEpochs(): JsonField = nEpochs - - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) - - companion object { - - /** - * Returns a mutable builder for constructing an instance of [Hyperparameters]. - */ - @JvmStatic fun builder() = Builder() - } - - /** A builder for [Hyperparameters]. */ - class Builder internal constructor() { - - private var batchSize: JsonField = JsonMissing.of() - private var learningRateMultiplier: JsonField = - JsonMissing.of() - private var nEpochs: JsonField = JsonMissing.of() - private var additionalProperties: MutableMap = mutableMapOf() - - @JvmSynthetic - internal fun from(hyperparameters: Hyperparameters) = apply { - batchSize = hyperparameters.batchSize - learningRateMultiplier = hyperparameters.learningRateMultiplier - nEpochs = hyperparameters.nEpochs - additionalProperties = hyperparameters.additionalProperties.toMutableMap() - } - - /** - * Number of examples in each batch. A larger batch size means that model - * parameters are updated less frequently, but with lower variance. - */ - fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) - - /** - * Sets [Builder.batchSize] to an arbitrary JSON value. - * - * You should usually call [Builder.batchSize] with a well-typed [BatchSize] - * value instead. This method is primarily for setting the field to an - * undocumented or not yet supported value. - */ - fun batchSize(batchSize: JsonField) = apply { - this.batchSize = batchSize - } - - /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ - fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) - - /** Alias for calling [batchSize] with `BatchSize.ofManual(manual)`. */ - fun batchSize(manual: Long) = batchSize(BatchSize.ofManual(manual)) - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful - * to avoid overfitting. - */ - fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = - learningRateMultiplier(JsonField.of(learningRateMultiplier)) - - /** - * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. - * - * You should usually call [Builder.learningRateMultiplier] with a well-typed - * [LearningRateMultiplier] value instead. This method is primarily for setting - * the field to an undocumented or not yet supported value. - */ - fun learningRateMultiplier( - learningRateMultiplier: JsonField - ) = apply { this.learningRateMultiplier = learningRateMultiplier } - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofAuto()`. - */ - fun learningRateMultiplierAuto() = - learningRateMultiplier(LearningRateMultiplier.ofAuto()) - - /** - * Alias for calling [learningRateMultiplier] with - * `LearningRateMultiplier.ofManual(manual)`. - */ - fun learningRateMultiplier(manual: Double) = - learningRateMultiplier(LearningRateMultiplier.ofManual(manual)) - - /** - * The number of epochs to train the model for. An epoch refers to one full - * cycle through the training dataset. - */ - fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) - - /** - * Sets [Builder.nEpochs] to an arbitrary JSON value. - * - * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value - * instead. This method is primarily for setting the field to an undocumented or - * not yet supported value. - */ - fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } - - /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ - fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) - - /** Alias for calling [nEpochs] with `NEpochs.ofManual(manual)`. */ - fun nEpochs(manual: Long) = nEpochs(NEpochs.ofManual(manual)) - - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } - - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } - - fun putAllAdditionalProperties(additionalProperties: Map) = - apply { - this.additionalProperties.putAll(additionalProperties) - } - - fun removeAdditionalProperty(key: String) = apply { - additionalProperties.remove(key) - } - - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } - - /** - * Returns an immutable instance of [Hyperparameters]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): Hyperparameters = - Hyperparameters( - batchSize, - learningRateMultiplier, - nEpochs, - additionalProperties.toMutableMap(), - ) - } - - private var validated: Boolean = false - - fun validate(): Hyperparameters = apply { - if (validated) { - return@apply - } - - batchSize().ifPresent { it.validate() } - learningRateMultiplier().ifPresent { it.validate() } - nEpochs().ifPresent { it.validate() } - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - (batchSize.asKnown().getOrNull()?.validity() ?: 0) + - (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + - (nEpochs.asKnown().getOrNull()?.validity() ?: 0) - - /** - * Number of examples in each batch. A larger batch size means that model parameters - * are updated less frequently, but with lower variance. - */ - @JsonDeserialize(using = BatchSize.Deserializer::class) - @JsonSerialize(using = BatchSize.Serializer::class) - class BatchSize - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): BatchSize = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is BatchSize && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "BatchSize{auto=$auto}" - manual != null -> "BatchSize{manual=$manual}" - _json != null -> "BatchSize{_unknown=$_json}" - else -> throw IllegalStateException("Invalid BatchSize") - } - - companion object { - - @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = BatchSize(manual = manual) - } - - /** - * An interface that defines how to map each variant of [BatchSize] to a value - * of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [BatchSize] to a value of type [T]. - * - * An instance of [BatchSize] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown BatchSize: $json") - } - } - - internal class Deserializer : BaseDeserializer(BatchSize::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { BatchSize(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - BatchSize(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> BatchSize(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(BatchSize::class) { - - override fun serialize( - value: BatchSize, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid BatchSize") - } - } - } - } - - /** - * Scaling factor for the learning rate. A smaller learning rate may be useful to - * avoid overfitting. - */ - @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) - @JsonSerialize(using = LearningRateMultiplier.Serializer::class) - class LearningRateMultiplier - private constructor( - private val auto: JsonValue? = null, - private val manual: Double? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Double = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): LearningRateMultiplier = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Double) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Double) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "LearningRateMultiplier{auto=$auto}" - manual != null -> "LearningRateMultiplier{manual=$manual}" - _json != null -> "LearningRateMultiplier{_unknown=$_json}" - else -> throw IllegalStateException("Invalid LearningRateMultiplier") - } - - companion object { - - @JvmStatic - fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) - - @JvmStatic - fun ofManual(manual: Double) = LearningRateMultiplier(manual = manual) - } - - /** - * An interface that defines how to map each variant of [LearningRateMultiplier] - * to a value of type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Double): T - - /** - * Maps an unknown variant of [LearningRateMultiplier] to a value of type - * [T]. - * - * An instance of [LearningRateMultiplier] can contain an unknown variant if - * it was deserialized from data that doesn't match any known variant. For - * example, if the SDK is on an older version than the API, then the API may - * respond with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException( - "Unknown LearningRateMultiplier: $json" - ) - } - } - - internal class Deserializer : - BaseDeserializer(LearningRateMultiplier::class) { - - override fun ObjectCodec.deserialize( - node: JsonNode - ): LearningRateMultiplier { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { - LearningRateMultiplier(auto = it, _json = json) - } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - LearningRateMultiplier(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> LearningRateMultiplier(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : - BaseSerializer(LearningRateMultiplier::class) { - - override fun serialize( - value: LearningRateMultiplier, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> - throw IllegalStateException("Invalid LearningRateMultiplier") - } - } - } - } - - /** - * The number of epochs to train the model for. An epoch refers to one full cycle - * through the training dataset. - */ - @JsonDeserialize(using = NEpochs.Deserializer::class) - @JsonSerialize(using = NEpochs.Serializer::class) - class NEpochs - private constructor( - private val auto: JsonValue? = null, - private val manual: Long? = null, - private val _json: JsonValue? = null, - ) { - - fun auto(): Optional = Optional.ofNullable(auto) - - fun manual(): Optional = Optional.ofNullable(manual) - - fun isAuto(): Boolean = auto != null - - fun isManual(): Boolean = manual != null - - fun asAuto(): JsonValue = auto.getOrThrow("auto") - - fun asManual(): Long = manual.getOrThrow("manual") - - fun _json(): Optional = Optional.ofNullable(_json) - - fun accept(visitor: Visitor): T = - when { - auto != null -> visitor.visitAuto(auto) - manual != null -> visitor.visitManual(manual) - else -> visitor.unknown(_json) - } - - private var validated: Boolean = false - - fun validate(): NEpochs = apply { - if (validated) { - return@apply - } - - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) { - auto.let { - if (it != JsonValue.from("auto")) { - throw OpenAIInvalidDataException( - "'auto' is invalid, received $it" - ) - } - } - } - - override fun visitManual(manual: Long) {} - } - ) - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: OpenAIInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic - internal fun validity(): Int = - accept( - object : Visitor { - override fun visitAuto(auto: JsonValue) = - auto.let { if (it == JsonValue.from("auto")) 1 else 0 } - - override fun visitManual(manual: Long) = 1 - - override fun unknown(json: JsonValue?) = 0 - } - ) - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is NEpochs && auto == other.auto && manual == other.manual /* spotless:on */ - } - - override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, manual) /* spotless:on */ - - override fun toString(): String = - when { - auto != null -> "NEpochs{auto=$auto}" - manual != null -> "NEpochs{manual=$manual}" - _json != null -> "NEpochs{_unknown=$_json}" - else -> throw IllegalStateException("Invalid NEpochs") - } - - companion object { - - @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) - - @JvmStatic fun ofManual(manual: Long) = NEpochs(manual = manual) - } - - /** - * An interface that defines how to map each variant of [NEpochs] to a value of - * type [T]. - */ - interface Visitor { - - fun visitAuto(auto: JsonValue): T - - fun visitManual(manual: Long): T - - /** - * Maps an unknown variant of [NEpochs] to a value of type [T]. - * - * An instance of [NEpochs] can contain an unknown variant if it was - * deserialized from data that doesn't match any known variant. For example, - * if the SDK is on an older version than the API, then the API may respond - * with new variants that the SDK is unaware of. - * - * @throws OpenAIInvalidDataException in the default implementation. - */ - fun unknown(json: JsonValue?): T { - throw OpenAIInvalidDataException("Unknown NEpochs: $json") - } - } - - internal class Deserializer : BaseDeserializer(NEpochs::class) { - - override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { - val json = JsonValue.fromJsonNode(node) - - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { NEpochs(auto = it, _json = json) } - ?.takeIf { it.isValid() }, - tryDeserialize(node, jacksonTypeRef())?.let { - NEpochs(manual = it, _json = json) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely - // incompatible with all the possible variants (e.g. deserializing - // from object). - 0 -> NEpochs(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then - // use the first completely valid match, or simply the first match - // if none are completely valid. - else -> - bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() - } - } - } - - internal class Serializer : BaseSerializer(NEpochs::class) { - - override fun serialize( - value: NEpochs, - generator: JsonGenerator, - provider: SerializerProvider, - ) { - when { - value.auto != null -> generator.writeObject(value.auto) - value.manual != null -> generator.writeObject(value.manual) - value._json != null -> generator.writeObject(value._json) - else -> throw IllegalStateException("Invalid NEpochs") - } - } - } - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Hyperparameters && batchSize == other.batchSize && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(batchSize, learningRateMultiplier, nEpochs, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Hyperparameters{batchSize=$batchSize, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, additionalProperties=$additionalProperties}" - } - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return /* spotless:off */ other is Supervised && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ - } - - /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(hyperparameters, additionalProperties) } - /* spotless:on */ - - override fun hashCode(): Int = hashCode - - override fun toString() = - "Supervised{hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" - } - - /** The type of method. Is either `supervised` or `dpo`. */ - class Type @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val SUPERVISED = of("supervised") - - @JvmField val DPO = of("dpo") + @JvmField val REINFORCEMENT = of("reinforcement") @JvmStatic fun of(value: String) = Type(JsonField.of(value)) } @@ -5290,6 +3123,7 @@ private constructor( enum class Known { SUPERVISED, DPO, + REINFORCEMENT, } /** @@ -5304,6 +3138,7 @@ private constructor( enum class Value { SUPERVISED, DPO, + REINFORCEMENT, /** An enum member indicating that [Type] was instantiated with an unknown value. */ _UNKNOWN, } @@ -5319,6 +3154,7 @@ private constructor( when (this) { SUPERVISED -> Value.SUPERVISED DPO -> Value.DPO + REINFORCEMENT -> Value.REINFORCEMENT else -> Value._UNKNOWN } @@ -5335,6 +3171,7 @@ private constructor( when (this) { SUPERVISED -> Known.SUPERVISED DPO -> Known.DPO + REINFORCEMENT -> Known.REINFORCEMENT else -> throw OpenAIInvalidDataException("Unknown Type: $value") } @@ -5397,17 +3234,17 @@ private constructor( return true } - return /* spotless:off */ other is Method && dpo == other.dpo && supervised == other.supervised && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is Method && type == other.type && dpo == other.dpo && reinforcement == other.reinforcement && supervised == other.supervised && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(dpo, supervised, type, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(type, dpo, reinforcement, supervised, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "Method{dpo=$dpo, supervised=$supervised, type=$type, additionalProperties=$additionalProperties}" + "Method{type=$type, dpo=$dpo, reinforcement=$reinforcement, supervised=$supervised, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPage.kt index 7acc932f3..2a93a6c82 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPage.kt @@ -2,12 +2,12 @@ package com.openai.models.finetuning.jobs +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.finetuning.JobService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [JobService.listEvents] */ @@ -16,7 +16,7 @@ private constructor( private val service: JobService, private val params: JobListEventsParams, private val response: JobListEventsPageResponse, -) { +) : Page { /** * Delegates to [JobListEventsPageResponse], but gracefully handles missing data. @@ -33,20 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): JobListEventsParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = - getNextPageParams().map { service.listEvents(it) } + override fun nextPage(): JobListEventsPage = service.listEvents(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): JobListEventsParams = params @@ -115,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: JobListEventsPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPageAsync.kt index eceb15680..2dc4a3e23 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.finetuning.jobs +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.finetuning.JobServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [JobServiceAsync.listEvents] */ class JobListEventsPageAsync private constructor( private val service: JobServiceAsync, + private val streamHandlerExecutor: Executor, private val params: JobListEventsParams, private val response: JobListEventsPageResponse, -) { +) : PageAsync { /** * Delegates to [JobListEventsPageResponse], but gracefully handles missing data. @@ -34,22 +36,18 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): JobListEventsParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.listEvents(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.listEvents(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): JobListEventsParams = params @@ -67,6 +65,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +77,24 @@ private constructor( class Builder internal constructor() { private var service: JobServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: JobListEventsParams? = null private var response: JobListEventsPageResponse? = null @JvmSynthetic internal fun from(jobListEventsPageAsync: JobListEventsPageAsync) = apply { service = jobListEventsPageAsync.service + streamHandlerExecutor = jobListEventsPageAsync.streamHandlerExecutor params = jobListEventsPageAsync.params response = jobListEventsPageAsync.response } fun service(service: JobServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: JobListEventsParams) = apply { this.params = params } @@ -104,6 +109,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +119,22 @@ private constructor( fun build(): JobListEventsPageAsync = JobListEventsPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: JobListEventsPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (FineTuningJobEvent) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is JobListEventsPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is JobListEventsPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "JobListEventsPageAsync{service=$service, params=$params, response=$response}" + "JobListEventsPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsParams.kt index 26348572d..1922578dc 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListEventsParams.kt @@ -3,7 +3,6 @@ package com.openai.models.finetuning.jobs import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects @@ -13,14 +12,14 @@ import kotlin.jvm.optionals.getOrNull /** Get status updates for a fine-tuning job. */ class JobListEventsParams private constructor( - private val fineTuningJobId: String, + private val fineTuningJobId: String?, private val after: String?, private val limit: Long?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun fineTuningJobId(): String = fineTuningJobId + fun fineTuningJobId(): Optional = Optional.ofNullable(fineTuningJobId) /** Identifier for the last event from the previous pagination request. */ fun after(): Optional = Optional.ofNullable(after) @@ -36,14 +35,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [JobListEventsParams]. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - */ + @JvmStatic fun none(): JobListEventsParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [JobListEventsParams]. */ @JvmStatic fun builder() = Builder() } @@ -65,10 +59,14 @@ private constructor( additionalQueryParams = jobListEventsParams.additionalQueryParams.toBuilder() } - fun fineTuningJobId(fineTuningJobId: String) = apply { + fun fineTuningJobId(fineTuningJobId: String?) = apply { this.fineTuningJobId = fineTuningJobId } + /** Alias for calling [Builder.fineTuningJobId] with `fineTuningJobId.orElse(null)`. */ + fun fineTuningJobId(fineTuningJobId: Optional) = + fineTuningJobId(fineTuningJobId.getOrNull()) + /** Identifier for the last event from the previous pagination request. */ fun after(after: String?) = apply { this.after = after } @@ -190,17 +188,10 @@ private constructor( * Returns an immutable instance of [JobListEventsParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): JobListEventsParams = JobListEventsParams( - checkRequired("fineTuningJobId", fineTuningJobId), + fineTuningJobId, after, limit, additionalHeaders.build(), @@ -210,7 +201,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fineTuningJobId + 0 -> fineTuningJobId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPage.kt index db6bcab0f..7ed9ed478 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.finetuning.jobs +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.finetuning.JobService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [JobService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: JobService, private val params: JobListParams, private val response: JobListPageResponse, -) { +) : Page { /** * Delegates to [JobListPageResponse], but gracefully handles missing data. @@ -33,19 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): JobListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): JobListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): JobListParams = params @@ -114,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: JobListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPageAsync.kt index 7730d2201..5860505d9 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.finetuning.jobs +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.finetuning.JobServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [JobServiceAsync.list] */ class JobListPageAsync private constructor( private val service: JobServiceAsync, + private val streamHandlerExecutor: Executor, private val params: JobListParams, private val response: JobListPageResponse, -) { +) : PageAsync { /** * Delegates to [JobListPageResponse], but gracefully handles missing data. @@ -34,22 +36,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): JobListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): JobListParams = params @@ -67,6 +64,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +76,24 @@ private constructor( class Builder internal constructor() { private var service: JobServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: JobListParams? = null private var response: JobListPageResponse? = null @JvmSynthetic internal fun from(jobListPageAsync: JobListPageAsync) = apply { service = jobListPageAsync.service + streamHandlerExecutor = jobListPageAsync.streamHandlerExecutor params = jobListPageAsync.params response = jobListPageAsync.response } fun service(service: JobServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: JobListParams) = apply { this.params = params } @@ -104,6 +108,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,47 +118,22 @@ private constructor( fun build(): JobListPageAsync = JobListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: JobListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (FineTuningJob) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is JobListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is JobListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "JobListPageAsync{service=$service, params=$params, response=$response}" + "JobListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobPauseParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobPauseParams.kt new file mode 100644 index 000000000..d4cc700b2 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobPauseParams.kt @@ -0,0 +1,224 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.jobs + +import com.openai.core.JsonValue +import com.openai.core.Params +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Pause a fine-tune job. */ +class JobPauseParams +private constructor( + private val fineTuningJobId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun fineTuningJobId(): Optional = Optional.ofNullable(fineTuningJobId) + + fun _additionalBodyProperties(): Map = additionalBodyProperties + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): JobPauseParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [JobPauseParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [JobPauseParams]. */ + class Builder internal constructor() { + + private var fineTuningJobId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(jobPauseParams: JobPauseParams) = apply { + fineTuningJobId = jobPauseParams.fineTuningJobId + additionalHeaders = jobPauseParams.additionalHeaders.toBuilder() + additionalQueryParams = jobPauseParams.additionalQueryParams.toBuilder() + additionalBodyProperties = jobPauseParams.additionalBodyProperties.toMutableMap() + } + + fun fineTuningJobId(fineTuningJobId: String?) = apply { + this.fineTuningJobId = fineTuningJobId + } + + /** Alias for calling [Builder.fineTuningJobId] with `fineTuningJobId.orElse(null)`. */ + fun fineTuningJobId(fineTuningJobId: Optional) = + fineTuningJobId(fineTuningJobId.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [JobPauseParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): JobPauseParams = + JobPauseParams( + fineTuningJobId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> fineTuningJobId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is JobPauseParams && fineTuningJobId == other.fineTuningJobId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(fineTuningJobId, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ + + override fun toString() = + "JobPauseParams{fineTuningJobId=$fineTuningJobId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobResumeParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobResumeParams.kt new file mode 100644 index 000000000..97f214e36 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobResumeParams.kt @@ -0,0 +1,224 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.jobs + +import com.openai.core.JsonValue +import com.openai.core.Params +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.toImmutable +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Resume a fine-tune job. */ +class JobResumeParams +private constructor( + private val fineTuningJobId: String?, + private val additionalHeaders: Headers, + private val additionalQueryParams: QueryParams, + private val additionalBodyProperties: Map, +) : Params { + + fun fineTuningJobId(): Optional = Optional.ofNullable(fineTuningJobId) + + fun _additionalBodyProperties(): Map = additionalBodyProperties + + fun _additionalHeaders(): Headers = additionalHeaders + + fun _additionalQueryParams(): QueryParams = additionalQueryParams + + fun toBuilder() = Builder().from(this) + + companion object { + + @JvmStatic fun none(): JobResumeParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [JobResumeParams]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [JobResumeParams]. */ + class Builder internal constructor() { + + private var fineTuningJobId: String? = null + private var additionalHeaders: Headers.Builder = Headers.builder() + private var additionalQueryParams: QueryParams.Builder = QueryParams.builder() + private var additionalBodyProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(jobResumeParams: JobResumeParams) = apply { + fineTuningJobId = jobResumeParams.fineTuningJobId + additionalHeaders = jobResumeParams.additionalHeaders.toBuilder() + additionalQueryParams = jobResumeParams.additionalQueryParams.toBuilder() + additionalBodyProperties = jobResumeParams.additionalBodyProperties.toMutableMap() + } + + fun fineTuningJobId(fineTuningJobId: String?) = apply { + this.fineTuningJobId = fineTuningJobId + } + + /** Alias for calling [Builder.fineTuningJobId] with `fineTuningJobId.orElse(null)`. */ + fun fineTuningJobId(fineTuningJobId: Optional) = + fineTuningJobId(fineTuningJobId.getOrNull()) + + fun additionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun additionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.clear() + putAllAdditionalHeaders(additionalHeaders) + } + + fun putAdditionalHeader(name: String, value: String) = apply { + additionalHeaders.put(name, value) + } + + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.put(name, values) + } + + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.putAll(additionalHeaders) + } + + fun replaceAdditionalHeaders(name: String, value: String) = apply { + additionalHeaders.replace(name, value) + } + + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + additionalHeaders.replace(name, values) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + this.additionalHeaders.replaceAll(additionalHeaders) + } + + fun removeAdditionalHeaders(name: String) = apply { additionalHeaders.remove(name) } + + fun removeAllAdditionalHeaders(names: Set) = apply { + additionalHeaders.removeAll(names) + } + + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + this.additionalQueryParams.clear() + putAllAdditionalQueryParams(additionalQueryParams) + } + + fun putAdditionalQueryParam(key: String, value: String) = apply { + additionalQueryParams.put(key, value) + } + + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.put(key, values) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.putAll(additionalQueryParams) + } + + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + additionalQueryParams.replace(key, value) + } + + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + additionalQueryParams.replace(key, values) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + this.additionalQueryParams.replaceAll(additionalQueryParams) + } + + fun removeAdditionalQueryParams(key: String) = apply { additionalQueryParams.remove(key) } + + fun removeAllAdditionalQueryParams(keys: Set) = apply { + additionalQueryParams.removeAll(keys) + } + + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + this.additionalBodyProperties.clear() + putAllAdditionalBodyProperties(additionalBodyProperties) + } + + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + additionalBodyProperties.put(key, value) + } + + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + this.additionalBodyProperties.putAll(additionalBodyProperties) + } + + fun removeAdditionalBodyProperty(key: String) = apply { + additionalBodyProperties.remove(key) + } + + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalBodyProperty) + } + + /** + * Returns an immutable instance of [JobResumeParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): JobResumeParams = + JobResumeParams( + fineTuningJobId, + additionalHeaders.build(), + additionalQueryParams.build(), + additionalBodyProperties.toImmutable(), + ) + } + + fun _body(): Optional> = + Optional.ofNullable(additionalBodyProperties.ifEmpty { null }) + + fun _pathParam(index: Int): String = + when (index) { + 0 -> fineTuningJobId ?: "" + else -> "" + } + + override fun _headers(): Headers = additionalHeaders + + override fun _queryParams(): QueryParams = additionalQueryParams + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is JobResumeParams && fineTuningJobId == other.fineTuningJobId && additionalHeaders == other.additionalHeaders && additionalQueryParams == other.additionalQueryParams && additionalBodyProperties == other.additionalBodyProperties /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(fineTuningJobId, additionalHeaders, additionalQueryParams, additionalBodyProperties) /* spotless:on */ + + override fun toString() = + "JobResumeParams{fineTuningJobId=$fineTuningJobId, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams, additionalBodyProperties=$additionalBodyProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobRetrieveParams.kt index 2e5e28749..3a5e08147 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/JobRetrieveParams.kt @@ -3,10 +3,11 @@ package com.openai.models.finetuning.jobs import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Get info about a fine-tuning job. @@ -15,12 +16,12 @@ import java.util.Objects */ class JobRetrieveParams private constructor( - private val fineTuningJobId: String, + private val fineTuningJobId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun fineTuningJobId(): String = fineTuningJobId + fun fineTuningJobId(): Optional = Optional.ofNullable(fineTuningJobId) fun _additionalHeaders(): Headers = additionalHeaders @@ -30,14 +31,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [JobRetrieveParams]. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - */ + @JvmStatic fun none(): JobRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [JobRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -55,10 +51,14 @@ private constructor( additionalQueryParams = jobRetrieveParams.additionalQueryParams.toBuilder() } - fun fineTuningJobId(fineTuningJobId: String) = apply { + fun fineTuningJobId(fineTuningJobId: String?) = apply { this.fineTuningJobId = fineTuningJobId } + /** Alias for calling [Builder.fineTuningJobId] with `fineTuningJobId.orElse(null)`. */ + fun fineTuningJobId(fineTuningJobId: Optional) = + fineTuningJobId(fineTuningJobId.getOrNull()) + fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() putAllAdditionalHeaders(additionalHeaders) @@ -161,17 +161,10 @@ private constructor( * Returns an immutable instance of [JobRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): JobRetrieveParams = JobRetrieveParams( - checkRequired("fineTuningJobId", fineTuningJobId), + fineTuningJobId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -179,7 +172,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fineTuningJobId + 0 -> fineTuningJobId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPage.kt index 64c6ce8be..e5df9890c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.finetuning.jobs.checkpoints +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.finetuning.jobs.CheckpointService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [CheckpointService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: CheckpointService, private val params: CheckpointListParams, private val response: CheckpointListPageResponse, -) { +) : Page { /** * Delegates to [CheckpointListPageResponse], but gracefully handles missing data. @@ -33,19 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): CheckpointListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): CheckpointListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): CheckpointListParams = params @@ -114,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: CheckpointListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPageAsync.kt index b5812ee75..4c377a567 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.finetuning.jobs.checkpoints +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.finetuning.jobs.CheckpointServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [CheckpointServiceAsync.list] */ class CheckpointListPageAsync private constructor( private val service: CheckpointServiceAsync, + private val streamHandlerExecutor: Executor, private val params: CheckpointListParams, private val response: CheckpointListPageResponse, -) { +) : PageAsync { /** * Delegates to [CheckpointListPageResponse], but gracefully handles missing data. @@ -34,22 +36,18 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): CheckpointListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): CheckpointListParams = params @@ -67,6 +65,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +77,24 @@ private constructor( class Builder internal constructor() { private var service: CheckpointServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: CheckpointListParams? = null private var response: CheckpointListPageResponse? = null @JvmSynthetic internal fun from(checkpointListPageAsync: CheckpointListPageAsync) = apply { service = checkpointListPageAsync.service + streamHandlerExecutor = checkpointListPageAsync.streamHandlerExecutor params = checkpointListPageAsync.params response = checkpointListPageAsync.response } fun service(service: CheckpointServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: CheckpointListParams) = apply { this.params = params } @@ -104,6 +109,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +119,22 @@ private constructor( fun build(): CheckpointListPageAsync = CheckpointListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: CheckpointListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (FineTuningJobCheckpoint) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is CheckpointListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is CheckpointListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "CheckpointListPageAsync{service=$service, params=$params, response=$response}" + "CheckpointListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListParams.kt index 917d04586..46483d0c3 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/jobs/checkpoints/CheckpointListParams.kt @@ -3,7 +3,6 @@ package com.openai.models.finetuning.jobs.checkpoints import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects @@ -13,14 +12,14 @@ import kotlin.jvm.optionals.getOrNull /** List checkpoints for a fine-tuning job. */ class CheckpointListParams private constructor( - private val fineTuningJobId: String, + private val fineTuningJobId: String?, private val after: String?, private val limit: Long?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun fineTuningJobId(): String = fineTuningJobId + fun fineTuningJobId(): Optional = Optional.ofNullable(fineTuningJobId) /** Identifier for the last checkpoint ID from the previous pagination request. */ fun after(): Optional = Optional.ofNullable(after) @@ -36,14 +35,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [CheckpointListParams]. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - */ + @JvmStatic fun none(): CheckpointListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [CheckpointListParams]. */ @JvmStatic fun builder() = Builder() } @@ -65,10 +59,14 @@ private constructor( additionalQueryParams = checkpointListParams.additionalQueryParams.toBuilder() } - fun fineTuningJobId(fineTuningJobId: String) = apply { + fun fineTuningJobId(fineTuningJobId: String?) = apply { this.fineTuningJobId = fineTuningJobId } + /** Alias for calling [Builder.fineTuningJobId] with `fineTuningJobId.orElse(null)`. */ + fun fineTuningJobId(fineTuningJobId: Optional) = + fineTuningJobId(fineTuningJobId.getOrNull()) + /** Identifier for the last checkpoint ID from the previous pagination request. */ fun after(after: String?) = apply { this.after = after } @@ -190,17 +188,10 @@ private constructor( * Returns an immutable instance of [CheckpointListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .fineTuningJobId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): CheckpointListParams = CheckpointListParams( - checkRequired("fineTuningJobId", fineTuningJobId), + fineTuningJobId, after, limit, additionalHeaders.build(), @@ -210,7 +201,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> fineTuningJobId + 0 -> fineTuningJobId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/DpoHyperparameters.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/DpoHyperparameters.kt new file mode 100644 index 000000000..e3c8b5c34 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/DpoHyperparameters.kt @@ -0,0 +1,1050 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.allMaxBy +import com.openai.core.getOrThrow +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** The hyperparameters used for the DPO fine-tuning job. */ +class DpoHyperparameters +private constructor( + private val batchSize: JsonField, + private val beta: JsonField, + private val learningRateMultiplier: JsonField, + private val nEpochs: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("batch_size") + @ExcludeMissing + batchSize: JsonField = JsonMissing.of(), + @JsonProperty("beta") @ExcludeMissing beta: JsonField = JsonMissing.of(), + @JsonProperty("learning_rate_multiplier") + @ExcludeMissing + learningRateMultiplier: JsonField = JsonMissing.of(), + @JsonProperty("n_epochs") @ExcludeMissing nEpochs: JsonField = JsonMissing.of(), + ) : this(batchSize, beta, learningRateMultiplier, nEpochs, mutableMapOf()) + + /** + * Number of examples in each batch. A larger batch size means that model parameters are updated + * less frequently, but with lower variance. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun batchSize(): Optional = batchSize.getOptional("batch_size") + + /** + * The beta value for the DPO method. A higher beta value will increase the weight of the + * penalty between the policy and reference model. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun beta(): Optional = beta.getOptional("beta") + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun learningRateMultiplier(): Optional = + learningRateMultiplier.getOptional("learning_rate_multiplier") + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through the + * training dataset. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") + + /** + * Returns the raw JSON value of [batchSize]. + * + * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("batch_size") @ExcludeMissing fun _batchSize(): JsonField = batchSize + + /** + * Returns the raw JSON value of [beta]. + * + * Unlike [beta], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("beta") @ExcludeMissing fun _beta(): JsonField = beta + + /** + * Returns the raw JSON value of [learningRateMultiplier]. + * + * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("learning_rate_multiplier") + @ExcludeMissing + fun _learningRateMultiplier(): JsonField = learningRateMultiplier + + /** + * Returns the raw JSON value of [nEpochs]. + * + * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("n_epochs") @ExcludeMissing fun _nEpochs(): JsonField = nEpochs + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [DpoHyperparameters]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [DpoHyperparameters]. */ + class Builder internal constructor() { + + private var batchSize: JsonField = JsonMissing.of() + private var beta: JsonField = JsonMissing.of() + private var learningRateMultiplier: JsonField = JsonMissing.of() + private var nEpochs: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(dpoHyperparameters: DpoHyperparameters) = apply { + batchSize = dpoHyperparameters.batchSize + beta = dpoHyperparameters.beta + learningRateMultiplier = dpoHyperparameters.learningRateMultiplier + nEpochs = dpoHyperparameters.nEpochs + additionalProperties = dpoHyperparameters.additionalProperties.toMutableMap() + } + + /** + * Number of examples in each batch. A larger batch size means that model parameters are + * updated less frequently, but with lower variance. + */ + fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) + + /** + * Sets [Builder.batchSize] to an arbitrary JSON value. + * + * You should usually call [Builder.batchSize] with a well-typed [BatchSize] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun batchSize(batchSize: JsonField) = apply { this.batchSize = batchSize } + + /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ + fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) + + /** Alias for calling [batchSize] with `BatchSize.ofInteger(integer)`. */ + fun batchSize(integer: Long) = batchSize(BatchSize.ofInteger(integer)) + + /** + * The beta value for the DPO method. A higher beta value will increase the weight of the + * penalty between the policy and reference model. + */ + fun beta(beta: Beta) = beta(JsonField.of(beta)) + + /** + * Sets [Builder.beta] to an arbitrary JSON value. + * + * You should usually call [Builder.beta] with a well-typed [Beta] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun beta(beta: JsonField) = apply { this.beta = beta } + + /** Alias for calling [beta] with `Beta.ofAuto()`. */ + fun betaAuto() = beta(Beta.ofAuto()) + + /** Alias for calling [beta] with `Beta.ofNumber(number)`. */ + fun beta(number: Double) = beta(Beta.ofNumber(number)) + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + */ + fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = + learningRateMultiplier(JsonField.of(learningRateMultiplier)) + + /** + * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. + * + * You should usually call [Builder.learningRateMultiplier] with a well-typed + * [LearningRateMultiplier] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun learningRateMultiplier(learningRateMultiplier: JsonField) = + apply { + this.learningRateMultiplier = learningRateMultiplier + } + + /** Alias for calling [learningRateMultiplier] with `LearningRateMultiplier.ofAuto()`. */ + fun learningRateMultiplierAuto() = learningRateMultiplier(LearningRateMultiplier.ofAuto()) + + /** + * Alias for calling [learningRateMultiplier] with + * `LearningRateMultiplier.ofNumber(number)`. + */ + fun learningRateMultiplier(number: Double) = + learningRateMultiplier(LearningRateMultiplier.ofNumber(number)) + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through + * the training dataset. + */ + fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) + + /** + * Sets [Builder.nEpochs] to an arbitrary JSON value. + * + * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } + + /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ + fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) + + /** Alias for calling [nEpochs] with `NEpochs.ofInteger(integer)`. */ + fun nEpochs(integer: Long) = nEpochs(NEpochs.ofInteger(integer)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [DpoHyperparameters]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): DpoHyperparameters = + DpoHyperparameters( + batchSize, + beta, + learningRateMultiplier, + nEpochs, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): DpoHyperparameters = apply { + if (validated) { + return@apply + } + + batchSize().ifPresent { it.validate() } + beta().ifPresent { it.validate() } + learningRateMultiplier().ifPresent { it.validate() } + nEpochs().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (batchSize.asKnown().getOrNull()?.validity() ?: 0) + + (beta.asKnown().getOrNull()?.validity() ?: 0) + + (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + + (nEpochs.asKnown().getOrNull()?.validity() ?: 0) + + /** + * Number of examples in each batch. A larger batch size means that model parameters are updated + * less frequently, but with lower variance. + */ + @JsonDeserialize(using = BatchSize.Deserializer::class) + @JsonSerialize(using = BatchSize.Serializer::class) + class BatchSize + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): BatchSize = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is BatchSize && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "BatchSize{auto=$auto}" + integer != null -> "BatchSize{integer=$integer}" + _json != null -> "BatchSize{_unknown=$_json}" + else -> throw IllegalStateException("Invalid BatchSize") + } + + companion object { + + @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = BatchSize(integer = integer) + } + + /** + * An interface that defines how to map each variant of [BatchSize] to a value of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [BatchSize] to a value of type [T]. + * + * An instance of [BatchSize] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown BatchSize: $json") + } + } + + internal class Deserializer : BaseDeserializer(BatchSize::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { BatchSize(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + BatchSize(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> BatchSize(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(BatchSize::class) { + + override fun serialize( + value: BatchSize, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid BatchSize") + } + } + } + } + + /** + * The beta value for the DPO method. A higher beta value will increase the weight of the + * penalty between the policy and reference model. + */ + @JsonDeserialize(using = Beta.Deserializer::class) + @JsonSerialize(using = Beta.Serializer::class) + class Beta + private constructor( + private val auto: JsonValue? = null, + private val number: Double? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun number(): Optional = Optional.ofNullable(number) + + fun isAuto(): Boolean = auto != null + + fun isNumber(): Boolean = number != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asNumber(): Double = number.getOrThrow("number") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + number != null -> visitor.visitNumber(number) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Beta = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitNumber(number: Double) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitNumber(number: Double) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Beta && auto == other.auto && number == other.number /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, number) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "Beta{auto=$auto}" + number != null -> "Beta{number=$number}" + _json != null -> "Beta{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Beta") + } + + companion object { + + @JvmStatic fun ofAuto() = Beta(auto = JsonValue.from("auto")) + + @JvmStatic fun ofNumber(number: Double) = Beta(number = number) + } + + /** An interface that defines how to map each variant of [Beta] to a value of type [T]. */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitNumber(number: Double): T + + /** + * Maps an unknown variant of [Beta] to a value of type [T]. + * + * An instance of [Beta] can contain an unknown variant if it was deserialized from data + * that doesn't match any known variant. For example, if the SDK is on an older version + * than the API, then the API may respond with new variants that the SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Beta: $json") + } + } + + internal class Deserializer : BaseDeserializer(Beta::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Beta { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { Beta(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + Beta(number = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> Beta(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Beta::class) { + + override fun serialize( + value: Beta, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.number != null -> generator.writeObject(value.number) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Beta") + } + } + } + } + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + */ + @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) + @JsonSerialize(using = LearningRateMultiplier.Serializer::class) + class LearningRateMultiplier + private constructor( + private val auto: JsonValue? = null, + private val number: Double? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun number(): Optional = Optional.ofNullable(number) + + fun isAuto(): Boolean = auto != null + + fun isNumber(): Boolean = number != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asNumber(): Double = number.getOrThrow("number") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + number != null -> visitor.visitNumber(number) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): LearningRateMultiplier = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitNumber(number: Double) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitNumber(number: Double) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && number == other.number /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, number) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "LearningRateMultiplier{auto=$auto}" + number != null -> "LearningRateMultiplier{number=$number}" + _json != null -> "LearningRateMultiplier{_unknown=$_json}" + else -> throw IllegalStateException("Invalid LearningRateMultiplier") + } + + companion object { + + @JvmStatic fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) + + @JvmStatic fun ofNumber(number: Double) = LearningRateMultiplier(number = number) + } + + /** + * An interface that defines how to map each variant of [LearningRateMultiplier] to a value + * of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitNumber(number: Double): T + + /** + * Maps an unknown variant of [LearningRateMultiplier] to a value of type [T]. + * + * An instance of [LearningRateMultiplier] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown LearningRateMultiplier: $json") + } + } + + internal class Deserializer : + BaseDeserializer(LearningRateMultiplier::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): LearningRateMultiplier { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { LearningRateMultiplier(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + LearningRateMultiplier(number = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> LearningRateMultiplier(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(LearningRateMultiplier::class) { + + override fun serialize( + value: LearningRateMultiplier, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.number != null -> generator.writeObject(value.number) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid LearningRateMultiplier") + } + } + } + } + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through the + * training dataset. + */ + @JsonDeserialize(using = NEpochs.Deserializer::class) + @JsonSerialize(using = NEpochs.Serializer::class) + class NEpochs + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): NEpochs = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is NEpochs && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "NEpochs{auto=$auto}" + integer != null -> "NEpochs{integer=$integer}" + _json != null -> "NEpochs{_unknown=$_json}" + else -> throw IllegalStateException("Invalid NEpochs") + } + + companion object { + + @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = NEpochs(integer = integer) + } + + /** + * An interface that defines how to map each variant of [NEpochs] to a value of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [NEpochs] to a value of type [T]. + * + * An instance of [NEpochs] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown NEpochs: $json") + } + } + + internal class Deserializer : BaseDeserializer(NEpochs::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { NEpochs(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + NEpochs(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> NEpochs(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(NEpochs::class) { + + override fun serialize( + value: NEpochs, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid NEpochs") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is DpoHyperparameters && batchSize == other.batchSize && beta == other.beta && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(batchSize, beta, learningRateMultiplier, nEpochs, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DpoHyperparameters{batchSize=$batchSize, beta=$beta, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/DpoMethod.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/DpoMethod.kt new file mode 100644 index 000000000..bc4896342 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/DpoMethod.kt @@ -0,0 +1,166 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Configuration for the DPO fine-tuning method. */ +class DpoMethod +private constructor( + private val hyperparameters: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("hyperparameters") + @ExcludeMissing + hyperparameters: JsonField = JsonMissing.of() + ) : this(hyperparameters, mutableMapOf()) + + /** + * The hyperparameters used for the DPO fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun hyperparameters(): Optional = + hyperparameters.getOptional("hyperparameters") + + /** + * Returns the raw JSON value of [hyperparameters]. + * + * Unlike [hyperparameters], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("hyperparameters") + @ExcludeMissing + fun _hyperparameters(): JsonField = hyperparameters + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [DpoMethod]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [DpoMethod]. */ + class Builder internal constructor() { + + private var hyperparameters: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(dpoMethod: DpoMethod) = apply { + hyperparameters = dpoMethod.hyperparameters + additionalProperties = dpoMethod.additionalProperties.toMutableMap() + } + + /** The hyperparameters used for the DPO fine-tuning job. */ + fun hyperparameters(hyperparameters: DpoHyperparameters) = + hyperparameters(JsonField.of(hyperparameters)) + + /** + * Sets [Builder.hyperparameters] to an arbitrary JSON value. + * + * You should usually call [Builder.hyperparameters] with a well-typed [DpoHyperparameters] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun hyperparameters(hyperparameters: JsonField) = apply { + this.hyperparameters = hyperparameters + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [DpoMethod]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): DpoMethod = DpoMethod(hyperparameters, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): DpoMethod = apply { + if (validated) { + return@apply + } + + hyperparameters().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is DpoMethod && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(hyperparameters, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "DpoMethod{hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/ReinforcementHyperparameters.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/ReinforcementHyperparameters.kt new file mode 100644 index 000000000..99840ec72 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/ReinforcementHyperparameters.kt @@ -0,0 +1,1703 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.Enum +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.allMaxBy +import com.openai.core.getOrThrow +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** The hyperparameters used for the reinforcement fine-tuning job. */ +class ReinforcementHyperparameters +private constructor( + private val batchSize: JsonField, + private val computeMultiplier: JsonField, + private val evalInterval: JsonField, + private val evalSamples: JsonField, + private val learningRateMultiplier: JsonField, + private val nEpochs: JsonField, + private val reasoningEffort: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("batch_size") + @ExcludeMissing + batchSize: JsonField = JsonMissing.of(), + @JsonProperty("compute_multiplier") + @ExcludeMissing + computeMultiplier: JsonField = JsonMissing.of(), + @JsonProperty("eval_interval") + @ExcludeMissing + evalInterval: JsonField = JsonMissing.of(), + @JsonProperty("eval_samples") + @ExcludeMissing + evalSamples: JsonField = JsonMissing.of(), + @JsonProperty("learning_rate_multiplier") + @ExcludeMissing + learningRateMultiplier: JsonField = JsonMissing.of(), + @JsonProperty("n_epochs") @ExcludeMissing nEpochs: JsonField = JsonMissing.of(), + @JsonProperty("reasoning_effort") + @ExcludeMissing + reasoningEffort: JsonField = JsonMissing.of(), + ) : this( + batchSize, + computeMultiplier, + evalInterval, + evalSamples, + learningRateMultiplier, + nEpochs, + reasoningEffort, + mutableMapOf(), + ) + + /** + * Number of examples in each batch. A larger batch size means that model parameters are updated + * less frequently, but with lower variance. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun batchSize(): Optional = batchSize.getOptional("batch_size") + + /** + * Multiplier on amount of compute used for exploring search space during training. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun computeMultiplier(): Optional = + computeMultiplier.getOptional("compute_multiplier") + + /** + * The number of training steps between evaluation runs. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun evalInterval(): Optional = evalInterval.getOptional("eval_interval") + + /** + * Number of evaluation samples to generate per training step. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun evalSamples(): Optional = evalSamples.getOptional("eval_samples") + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun learningRateMultiplier(): Optional = + learningRateMultiplier.getOptional("learning_rate_multiplier") + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through the + * training dataset. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") + + /** + * Level of reasoning effort. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun reasoningEffort(): Optional = + reasoningEffort.getOptional("reasoning_effort") + + /** + * Returns the raw JSON value of [batchSize]. + * + * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("batch_size") @ExcludeMissing fun _batchSize(): JsonField = batchSize + + /** + * Returns the raw JSON value of [computeMultiplier]. + * + * Unlike [computeMultiplier], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("compute_multiplier") + @ExcludeMissing + fun _computeMultiplier(): JsonField = computeMultiplier + + /** + * Returns the raw JSON value of [evalInterval]. + * + * Unlike [evalInterval], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("eval_interval") + @ExcludeMissing + fun _evalInterval(): JsonField = evalInterval + + /** + * Returns the raw JSON value of [evalSamples]. + * + * Unlike [evalSamples], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("eval_samples") + @ExcludeMissing + fun _evalSamples(): JsonField = evalSamples + + /** + * Returns the raw JSON value of [learningRateMultiplier]. + * + * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("learning_rate_multiplier") + @ExcludeMissing + fun _learningRateMultiplier(): JsonField = learningRateMultiplier + + /** + * Returns the raw JSON value of [nEpochs]. + * + * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("n_epochs") @ExcludeMissing fun _nEpochs(): JsonField = nEpochs + + /** + * Returns the raw JSON value of [reasoningEffort]. + * + * Unlike [reasoningEffort], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("reasoning_effort") + @ExcludeMissing + fun _reasoningEffort(): JsonField = reasoningEffort + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ReinforcementHyperparameters]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ReinforcementHyperparameters]. */ + class Builder internal constructor() { + + private var batchSize: JsonField = JsonMissing.of() + private var computeMultiplier: JsonField = JsonMissing.of() + private var evalInterval: JsonField = JsonMissing.of() + private var evalSamples: JsonField = JsonMissing.of() + private var learningRateMultiplier: JsonField = JsonMissing.of() + private var nEpochs: JsonField = JsonMissing.of() + private var reasoningEffort: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(reinforcementHyperparameters: ReinforcementHyperparameters) = apply { + batchSize = reinforcementHyperparameters.batchSize + computeMultiplier = reinforcementHyperparameters.computeMultiplier + evalInterval = reinforcementHyperparameters.evalInterval + evalSamples = reinforcementHyperparameters.evalSamples + learningRateMultiplier = reinforcementHyperparameters.learningRateMultiplier + nEpochs = reinforcementHyperparameters.nEpochs + reasoningEffort = reinforcementHyperparameters.reasoningEffort + additionalProperties = reinforcementHyperparameters.additionalProperties.toMutableMap() + } + + /** + * Number of examples in each batch. A larger batch size means that model parameters are + * updated less frequently, but with lower variance. + */ + fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) + + /** + * Sets [Builder.batchSize] to an arbitrary JSON value. + * + * You should usually call [Builder.batchSize] with a well-typed [BatchSize] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun batchSize(batchSize: JsonField) = apply { this.batchSize = batchSize } + + /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ + fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) + + /** Alias for calling [batchSize] with `BatchSize.ofInteger(integer)`. */ + fun batchSize(integer: Long) = batchSize(BatchSize.ofInteger(integer)) + + /** Multiplier on amount of compute used for exploring search space during training. */ + fun computeMultiplier(computeMultiplier: ComputeMultiplier) = + computeMultiplier(JsonField.of(computeMultiplier)) + + /** + * Sets [Builder.computeMultiplier] to an arbitrary JSON value. + * + * You should usually call [Builder.computeMultiplier] with a well-typed [ComputeMultiplier] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun computeMultiplier(computeMultiplier: JsonField) = apply { + this.computeMultiplier = computeMultiplier + } + + /** Alias for calling [computeMultiplier] with `ComputeMultiplier.ofAuto()`. */ + fun computeMultiplierAuto() = computeMultiplier(ComputeMultiplier.ofAuto()) + + /** Alias for calling [computeMultiplier] with `ComputeMultiplier.ofNumber(number)`. */ + fun computeMultiplier(number: Double) = + computeMultiplier(ComputeMultiplier.ofNumber(number)) + + /** The number of training steps between evaluation runs. */ + fun evalInterval(evalInterval: EvalInterval) = evalInterval(JsonField.of(evalInterval)) + + /** + * Sets [Builder.evalInterval] to an arbitrary JSON value. + * + * You should usually call [Builder.evalInterval] with a well-typed [EvalInterval] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun evalInterval(evalInterval: JsonField) = apply { + this.evalInterval = evalInterval + } + + /** Alias for calling [evalInterval] with `EvalInterval.ofAuto()`. */ + fun evalIntervalAuto() = evalInterval(EvalInterval.ofAuto()) + + /** Alias for calling [evalInterval] with `EvalInterval.ofInteger(integer)`. */ + fun evalInterval(integer: Long) = evalInterval(EvalInterval.ofInteger(integer)) + + /** Number of evaluation samples to generate per training step. */ + fun evalSamples(evalSamples: EvalSamples) = evalSamples(JsonField.of(evalSamples)) + + /** + * Sets [Builder.evalSamples] to an arbitrary JSON value. + * + * You should usually call [Builder.evalSamples] with a well-typed [EvalSamples] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun evalSamples(evalSamples: JsonField) = apply { + this.evalSamples = evalSamples + } + + /** Alias for calling [evalSamples] with `EvalSamples.ofAuto()`. */ + fun evalSamplesAuto() = evalSamples(EvalSamples.ofAuto()) + + /** Alias for calling [evalSamples] with `EvalSamples.ofInteger(integer)`. */ + fun evalSamples(integer: Long) = evalSamples(EvalSamples.ofInteger(integer)) + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + */ + fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = + learningRateMultiplier(JsonField.of(learningRateMultiplier)) + + /** + * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. + * + * You should usually call [Builder.learningRateMultiplier] with a well-typed + * [LearningRateMultiplier] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun learningRateMultiplier(learningRateMultiplier: JsonField) = + apply { + this.learningRateMultiplier = learningRateMultiplier + } + + /** Alias for calling [learningRateMultiplier] with `LearningRateMultiplier.ofAuto()`. */ + fun learningRateMultiplierAuto() = learningRateMultiplier(LearningRateMultiplier.ofAuto()) + + /** + * Alias for calling [learningRateMultiplier] with + * `LearningRateMultiplier.ofNumber(number)`. + */ + fun learningRateMultiplier(number: Double) = + learningRateMultiplier(LearningRateMultiplier.ofNumber(number)) + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through + * the training dataset. + */ + fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) + + /** + * Sets [Builder.nEpochs] to an arbitrary JSON value. + * + * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } + + /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ + fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) + + /** Alias for calling [nEpochs] with `NEpochs.ofInteger(integer)`. */ + fun nEpochs(integer: Long) = nEpochs(NEpochs.ofInteger(integer)) + + /** Level of reasoning effort. */ + fun reasoningEffort(reasoningEffort: ReasoningEffort) = + reasoningEffort(JsonField.of(reasoningEffort)) + + /** + * Sets [Builder.reasoningEffort] to an arbitrary JSON value. + * + * You should usually call [Builder.reasoningEffort] with a well-typed [ReasoningEffort] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun reasoningEffort(reasoningEffort: JsonField) = apply { + this.reasoningEffort = reasoningEffort + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ReinforcementHyperparameters]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): ReinforcementHyperparameters = + ReinforcementHyperparameters( + batchSize, + computeMultiplier, + evalInterval, + evalSamples, + learningRateMultiplier, + nEpochs, + reasoningEffort, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ReinforcementHyperparameters = apply { + if (validated) { + return@apply + } + + batchSize().ifPresent { it.validate() } + computeMultiplier().ifPresent { it.validate() } + evalInterval().ifPresent { it.validate() } + evalSamples().ifPresent { it.validate() } + learningRateMultiplier().ifPresent { it.validate() } + nEpochs().ifPresent { it.validate() } + reasoningEffort().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (batchSize.asKnown().getOrNull()?.validity() ?: 0) + + (computeMultiplier.asKnown().getOrNull()?.validity() ?: 0) + + (evalInterval.asKnown().getOrNull()?.validity() ?: 0) + + (evalSamples.asKnown().getOrNull()?.validity() ?: 0) + + (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + + (nEpochs.asKnown().getOrNull()?.validity() ?: 0) + + (reasoningEffort.asKnown().getOrNull()?.validity() ?: 0) + + /** + * Number of examples in each batch. A larger batch size means that model parameters are updated + * less frequently, but with lower variance. + */ + @JsonDeserialize(using = BatchSize.Deserializer::class) + @JsonSerialize(using = BatchSize.Serializer::class) + class BatchSize + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): BatchSize = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is BatchSize && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "BatchSize{auto=$auto}" + integer != null -> "BatchSize{integer=$integer}" + _json != null -> "BatchSize{_unknown=$_json}" + else -> throw IllegalStateException("Invalid BatchSize") + } + + companion object { + + @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = BatchSize(integer = integer) + } + + /** + * An interface that defines how to map each variant of [BatchSize] to a value of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [BatchSize] to a value of type [T]. + * + * An instance of [BatchSize] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown BatchSize: $json") + } + } + + internal class Deserializer : BaseDeserializer(BatchSize::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { BatchSize(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + BatchSize(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> BatchSize(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(BatchSize::class) { + + override fun serialize( + value: BatchSize, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid BatchSize") + } + } + } + } + + /** Multiplier on amount of compute used for exploring search space during training. */ + @JsonDeserialize(using = ComputeMultiplier.Deserializer::class) + @JsonSerialize(using = ComputeMultiplier.Serializer::class) + class ComputeMultiplier + private constructor( + private val auto: JsonValue? = null, + private val number: Double? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun number(): Optional = Optional.ofNullable(number) + + fun isAuto(): Boolean = auto != null + + fun isNumber(): Boolean = number != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asNumber(): Double = number.getOrThrow("number") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + number != null -> visitor.visitNumber(number) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): ComputeMultiplier = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitNumber(number: Double) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitNumber(number: Double) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ComputeMultiplier && auto == other.auto && number == other.number /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, number) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "ComputeMultiplier{auto=$auto}" + number != null -> "ComputeMultiplier{number=$number}" + _json != null -> "ComputeMultiplier{_unknown=$_json}" + else -> throw IllegalStateException("Invalid ComputeMultiplier") + } + + companion object { + + @JvmStatic fun ofAuto() = ComputeMultiplier(auto = JsonValue.from("auto")) + + @JvmStatic fun ofNumber(number: Double) = ComputeMultiplier(number = number) + } + + /** + * An interface that defines how to map each variant of [ComputeMultiplier] to a value of + * type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitNumber(number: Double): T + + /** + * Maps an unknown variant of [ComputeMultiplier] to a value of type [T]. + * + * An instance of [ComputeMultiplier] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown ComputeMultiplier: $json") + } + } + + internal class Deserializer : + BaseDeserializer(ComputeMultiplier::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): ComputeMultiplier { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { ComputeMultiplier(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + ComputeMultiplier(number = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> ComputeMultiplier(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(ComputeMultiplier::class) { + + override fun serialize( + value: ComputeMultiplier, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.number != null -> generator.writeObject(value.number) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid ComputeMultiplier") + } + } + } + } + + /** The number of training steps between evaluation runs. */ + @JsonDeserialize(using = EvalInterval.Deserializer::class) + @JsonSerialize(using = EvalInterval.Serializer::class) + class EvalInterval + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): EvalInterval = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is EvalInterval && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "EvalInterval{auto=$auto}" + integer != null -> "EvalInterval{integer=$integer}" + _json != null -> "EvalInterval{_unknown=$_json}" + else -> throw IllegalStateException("Invalid EvalInterval") + } + + companion object { + + @JvmStatic fun ofAuto() = EvalInterval(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = EvalInterval(integer = integer) + } + + /** + * An interface that defines how to map each variant of [EvalInterval] to a value of type + * [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [EvalInterval] to a value of type [T]. + * + * An instance of [EvalInterval] can contain an unknown variant if it was deserialized + * from data that doesn't match any known variant. For example, if the SDK is on an + * older version than the API, then the API may respond with new variants that the SDK + * is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown EvalInterval: $json") + } + } + + internal class Deserializer : BaseDeserializer(EvalInterval::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): EvalInterval { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { EvalInterval(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + EvalInterval(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> EvalInterval(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(EvalInterval::class) { + + override fun serialize( + value: EvalInterval, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid EvalInterval") + } + } + } + } + + /** Number of evaluation samples to generate per training step. */ + @JsonDeserialize(using = EvalSamples.Deserializer::class) + @JsonSerialize(using = EvalSamples.Serializer::class) + class EvalSamples + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): EvalSamples = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is EvalSamples && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "EvalSamples{auto=$auto}" + integer != null -> "EvalSamples{integer=$integer}" + _json != null -> "EvalSamples{_unknown=$_json}" + else -> throw IllegalStateException("Invalid EvalSamples") + } + + companion object { + + @JvmStatic fun ofAuto() = EvalSamples(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = EvalSamples(integer = integer) + } + + /** + * An interface that defines how to map each variant of [EvalSamples] to a value of type + * [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [EvalSamples] to a value of type [T]. + * + * An instance of [EvalSamples] can contain an unknown variant if it was deserialized + * from data that doesn't match any known variant. For example, if the SDK is on an + * older version than the API, then the API may respond with new variants that the SDK + * is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown EvalSamples: $json") + } + } + + internal class Deserializer : BaseDeserializer(EvalSamples::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): EvalSamples { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { EvalSamples(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + EvalSamples(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> EvalSamples(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(EvalSamples::class) { + + override fun serialize( + value: EvalSamples, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid EvalSamples") + } + } + } + } + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + */ + @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) + @JsonSerialize(using = LearningRateMultiplier.Serializer::class) + class LearningRateMultiplier + private constructor( + private val auto: JsonValue? = null, + private val number: Double? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun number(): Optional = Optional.ofNullable(number) + + fun isAuto(): Boolean = auto != null + + fun isNumber(): Boolean = number != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asNumber(): Double = number.getOrThrow("number") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + number != null -> visitor.visitNumber(number) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): LearningRateMultiplier = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitNumber(number: Double) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitNumber(number: Double) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && number == other.number /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, number) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "LearningRateMultiplier{auto=$auto}" + number != null -> "LearningRateMultiplier{number=$number}" + _json != null -> "LearningRateMultiplier{_unknown=$_json}" + else -> throw IllegalStateException("Invalid LearningRateMultiplier") + } + + companion object { + + @JvmStatic fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) + + @JvmStatic fun ofNumber(number: Double) = LearningRateMultiplier(number = number) + } + + /** + * An interface that defines how to map each variant of [LearningRateMultiplier] to a value + * of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitNumber(number: Double): T + + /** + * Maps an unknown variant of [LearningRateMultiplier] to a value of type [T]. + * + * An instance of [LearningRateMultiplier] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown LearningRateMultiplier: $json") + } + } + + internal class Deserializer : + BaseDeserializer(LearningRateMultiplier::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): LearningRateMultiplier { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { LearningRateMultiplier(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + LearningRateMultiplier(number = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> LearningRateMultiplier(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(LearningRateMultiplier::class) { + + override fun serialize( + value: LearningRateMultiplier, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.number != null -> generator.writeObject(value.number) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid LearningRateMultiplier") + } + } + } + } + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through the + * training dataset. + */ + @JsonDeserialize(using = NEpochs.Deserializer::class) + @JsonSerialize(using = NEpochs.Serializer::class) + class NEpochs + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): NEpochs = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is NEpochs && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "NEpochs{auto=$auto}" + integer != null -> "NEpochs{integer=$integer}" + _json != null -> "NEpochs{_unknown=$_json}" + else -> throw IllegalStateException("Invalid NEpochs") + } + + companion object { + + @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = NEpochs(integer = integer) + } + + /** + * An interface that defines how to map each variant of [NEpochs] to a value of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [NEpochs] to a value of type [T]. + * + * An instance of [NEpochs] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown NEpochs: $json") + } + } + + internal class Deserializer : BaseDeserializer(NEpochs::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { NEpochs(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + NEpochs(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> NEpochs(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(NEpochs::class) { + + override fun serialize( + value: NEpochs, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid NEpochs") + } + } + } + } + + /** Level of reasoning effort. */ + class ReasoningEffort @JsonCreator private constructor(private val value: JsonField) : + Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val DEFAULT = of("default") + + @JvmField val LOW = of("low") + + @JvmField val MEDIUM = of("medium") + + @JvmField val HIGH = of("high") + + @JvmStatic fun of(value: String) = ReasoningEffort(JsonField.of(value)) + } + + /** An enum containing [ReasoningEffort]'s known values. */ + enum class Known { + DEFAULT, + LOW, + MEDIUM, + HIGH, + } + + /** + * An enum containing [ReasoningEffort]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [ReasoningEffort] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + DEFAULT, + LOW, + MEDIUM, + HIGH, + /** + * An enum member indicating that [ReasoningEffort] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + DEFAULT -> Value.DEFAULT + LOW -> Value.LOW + MEDIUM -> Value.MEDIUM + HIGH -> Value.HIGH + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + DEFAULT -> Known.DEFAULT + LOW -> Known.LOW + MEDIUM -> Known.MEDIUM + HIGH -> Known.HIGH + else -> throw OpenAIInvalidDataException("Unknown ReasoningEffort: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { OpenAIInvalidDataException("Value is not a String") } + + private var validated: Boolean = false + + fun validate(): ReasoningEffort = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ReasoningEffort && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ReinforcementHyperparameters && batchSize == other.batchSize && computeMultiplier == other.computeMultiplier && evalInterval == other.evalInterval && evalSamples == other.evalSamples && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && reasoningEffort == other.reasoningEffort && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(batchSize, computeMultiplier, evalInterval, evalSamples, learningRateMultiplier, nEpochs, reasoningEffort, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ReinforcementHyperparameters{batchSize=$batchSize, computeMultiplier=$computeMultiplier, evalInterval=$evalInterval, evalSamples=$evalSamples, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, reasoningEffort=$reasoningEffort, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/ReinforcementMethod.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/ReinforcementMethod.kt new file mode 100644 index 000000000..423082eea --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/ReinforcementMethod.kt @@ -0,0 +1,541 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.allMaxBy +import com.openai.core.checkRequired +import com.openai.core.getOrThrow +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.graders.gradermodels.MultiGrader +import com.openai.models.graders.gradermodels.PythonGrader +import com.openai.models.graders.gradermodels.ScoreModelGrader +import com.openai.models.graders.gradermodels.StringCheckGrader +import com.openai.models.graders.gradermodels.TextSimilarityGrader +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Configuration for the reinforcement fine-tuning method. */ +class ReinforcementMethod +private constructor( + private val grader: JsonField, + private val hyperparameters: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("grader") @ExcludeMissing grader: JsonField = JsonMissing.of(), + @JsonProperty("hyperparameters") + @ExcludeMissing + hyperparameters: JsonField = JsonMissing.of(), + ) : this(grader, hyperparameters, mutableMapOf()) + + /** + * The grader used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun grader(): Grader = grader.getRequired("grader") + + /** + * The hyperparameters used for the reinforcement fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun hyperparameters(): Optional = + hyperparameters.getOptional("hyperparameters") + + /** + * Returns the raw JSON value of [grader]. + * + * Unlike [grader], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("grader") @ExcludeMissing fun _grader(): JsonField = grader + + /** + * Returns the raw JSON value of [hyperparameters]. + * + * Unlike [hyperparameters], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("hyperparameters") + @ExcludeMissing + fun _hyperparameters(): JsonField = hyperparameters + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ReinforcementMethod]. + * + * The following fields are required: + * ```java + * .grader() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ReinforcementMethod]. */ + class Builder internal constructor() { + + private var grader: JsonField? = null + private var hyperparameters: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(reinforcementMethod: ReinforcementMethod) = apply { + grader = reinforcementMethod.grader + hyperparameters = reinforcementMethod.hyperparameters + additionalProperties = reinforcementMethod.additionalProperties.toMutableMap() + } + + /** The grader used for the fine-tuning job. */ + fun grader(grader: Grader) = grader(JsonField.of(grader)) + + /** + * Sets [Builder.grader] to an arbitrary JSON value. + * + * You should usually call [Builder.grader] with a well-typed [Grader] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun grader(grader: JsonField) = apply { this.grader = grader } + + /** Alias for calling [grader] with `Grader.ofStringCheck(stringCheck)`. */ + fun grader(stringCheck: StringCheckGrader) = grader(Grader.ofStringCheck(stringCheck)) + + /** Alias for calling [grader] with `Grader.ofTextSimilarity(textSimilarity)`. */ + fun grader(textSimilarity: TextSimilarityGrader) = + grader(Grader.ofTextSimilarity(textSimilarity)) + + /** Alias for calling [grader] with `Grader.ofPython(python)`. */ + fun grader(python: PythonGrader) = grader(Grader.ofPython(python)) + + /** Alias for calling [grader] with `Grader.ofScoreModel(scoreModel)`. */ + fun grader(scoreModel: ScoreModelGrader) = grader(Grader.ofScoreModel(scoreModel)) + + /** Alias for calling [grader] with `Grader.ofMulti(multi)`. */ + fun grader(multi: MultiGrader) = grader(Grader.ofMulti(multi)) + + /** The hyperparameters used for the reinforcement fine-tuning job. */ + fun hyperparameters(hyperparameters: ReinforcementHyperparameters) = + hyperparameters(JsonField.of(hyperparameters)) + + /** + * Sets [Builder.hyperparameters] to an arbitrary JSON value. + * + * You should usually call [Builder.hyperparameters] with a well-typed + * [ReinforcementHyperparameters] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun hyperparameters(hyperparameters: JsonField) = apply { + this.hyperparameters = hyperparameters + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ReinforcementMethod]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .grader() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ReinforcementMethod = + ReinforcementMethod( + checkRequired("grader", grader), + hyperparameters, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ReinforcementMethod = apply { + if (validated) { + return@apply + } + + grader().validate() + hyperparameters().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (grader.asKnown().getOrNull()?.validity() ?: 0) + + (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) + + /** The grader used for the fine-tuning job. */ + @JsonDeserialize(using = Grader.Deserializer::class) + @JsonSerialize(using = Grader.Serializer::class) + class Grader + private constructor( + private val stringCheck: StringCheckGrader? = null, + private val textSimilarity: TextSimilarityGrader? = null, + private val python: PythonGrader? = null, + private val scoreModel: ScoreModelGrader? = null, + private val multi: MultiGrader? = null, + private val _json: JsonValue? = null, + ) { + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun stringCheck(): Optional = Optional.ofNullable(stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun textSimilarity(): Optional = Optional.ofNullable(textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + fun python(): Optional = Optional.ofNullable(python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun scoreModel(): Optional = Optional.ofNullable(scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun multi(): Optional = Optional.ofNullable(multi) + + fun isStringCheck(): Boolean = stringCheck != null + + fun isTextSimilarity(): Boolean = textSimilarity != null + + fun isPython(): Boolean = python != null + + fun isScoreModel(): Boolean = scoreModel != null + + fun isMulti(): Boolean = multi != null + + /** + * A StringCheckGrader object that performs a string comparison between input and reference + * using a specified operation. + */ + fun asStringCheck(): StringCheckGrader = stringCheck.getOrThrow("stringCheck") + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun asTextSimilarity(): TextSimilarityGrader = textSimilarity.getOrThrow("textSimilarity") + + /** A PythonGrader object that runs a python script on the input. */ + fun asPython(): PythonGrader = python.getOrThrow("python") + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun asScoreModel(): ScoreModelGrader = scoreModel.getOrThrow("scoreModel") + + /** + * A MultiGrader object combines the output of multiple graders to produce a single score. + */ + fun asMulti(): MultiGrader = multi.getOrThrow("multi") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + stringCheck != null -> visitor.visitStringCheck(stringCheck) + textSimilarity != null -> visitor.visitTextSimilarity(textSimilarity) + python != null -> visitor.visitPython(python) + scoreModel != null -> visitor.visitScoreModel(scoreModel) + multi != null -> visitor.visitMulti(multi) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Grader = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) { + stringCheck.validate() + } + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) { + textSimilarity.validate() + } + + override fun visitPython(python: PythonGrader) { + python.validate() + } + + override fun visitScoreModel(scoreModel: ScoreModelGrader) { + scoreModel.validate() + } + + override fun visitMulti(multi: MultiGrader) { + multi.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitStringCheck(stringCheck: StringCheckGrader) = + stringCheck.validity() + + override fun visitTextSimilarity(textSimilarity: TextSimilarityGrader) = + textSimilarity.validity() + + override fun visitPython(python: PythonGrader) = python.validity() + + override fun visitScoreModel(scoreModel: ScoreModelGrader) = + scoreModel.validity() + + override fun visitMulti(multi: MultiGrader) = multi.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Grader && stringCheck == other.stringCheck && textSimilarity == other.textSimilarity && python == other.python && scoreModel == other.scoreModel && multi == other.multi /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(stringCheck, textSimilarity, python, scoreModel, multi) /* spotless:on */ + + override fun toString(): String = + when { + stringCheck != null -> "Grader{stringCheck=$stringCheck}" + textSimilarity != null -> "Grader{textSimilarity=$textSimilarity}" + python != null -> "Grader{python=$python}" + scoreModel != null -> "Grader{scoreModel=$scoreModel}" + multi != null -> "Grader{multi=$multi}" + _json != null -> "Grader{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Grader") + } + + companion object { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + @JvmStatic + fun ofStringCheck(stringCheck: StringCheckGrader) = Grader(stringCheck = stringCheck) + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + @JvmStatic + fun ofTextSimilarity(textSimilarity: TextSimilarityGrader) = + Grader(textSimilarity = textSimilarity) + + /** A PythonGrader object that runs a python script on the input. */ + @JvmStatic fun ofPython(python: PythonGrader) = Grader(python = python) + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + @JvmStatic + fun ofScoreModel(scoreModel: ScoreModelGrader) = Grader(scoreModel = scoreModel) + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + @JvmStatic fun ofMulti(multi: MultiGrader) = Grader(multi = multi) + } + + /** An interface that defines how to map each variant of [Grader] to a value of type [T]. */ + interface Visitor { + + /** + * A StringCheckGrader object that performs a string comparison between input and + * reference using a specified operation. + */ + fun visitStringCheck(stringCheck: StringCheckGrader): T + + /** A TextSimilarityGrader object which grades text based on similarity metrics. */ + fun visitTextSimilarity(textSimilarity: TextSimilarityGrader): T + + /** A PythonGrader object that runs a python script on the input. */ + fun visitPython(python: PythonGrader): T + + /** A ScoreModelGrader object that uses a model to assign a score to the input. */ + fun visitScoreModel(scoreModel: ScoreModelGrader): T + + /** + * A MultiGrader object combines the output of multiple graders to produce a single + * score. + */ + fun visitMulti(multi: MultiGrader): T + + /** + * Maps an unknown variant of [Grader] to a value of type [T]. + * + * An instance of [Grader] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Grader: $json") + } + } + + internal class Deserializer : BaseDeserializer(Grader::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Grader { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(stringCheck = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(textSimilarity = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(python = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(scoreModel = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Grader(multi = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from boolean). + 0 -> Grader(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Grader::class) { + + override fun serialize( + value: Grader, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.stringCheck != null -> generator.writeObject(value.stringCheck) + value.textSimilarity != null -> generator.writeObject(value.textSimilarity) + value.python != null -> generator.writeObject(value.python) + value.scoreModel != null -> generator.writeObject(value.scoreModel) + value.multi != null -> generator.writeObject(value.multi) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Grader") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ReinforcementMethod && grader == other.grader && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(grader, hyperparameters, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ReinforcementMethod{grader=$grader, hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/SupervisedHyperparameters.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/SupervisedHyperparameters.kt new file mode 100644 index 000000000..92aa0e794 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/SupervisedHyperparameters.kt @@ -0,0 +1,832 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.allMaxBy +import com.openai.core.getOrThrow +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** The hyperparameters used for the fine-tuning job. */ +class SupervisedHyperparameters +private constructor( + private val batchSize: JsonField, + private val learningRateMultiplier: JsonField, + private val nEpochs: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("batch_size") + @ExcludeMissing + batchSize: JsonField = JsonMissing.of(), + @JsonProperty("learning_rate_multiplier") + @ExcludeMissing + learningRateMultiplier: JsonField = JsonMissing.of(), + @JsonProperty("n_epochs") @ExcludeMissing nEpochs: JsonField = JsonMissing.of(), + ) : this(batchSize, learningRateMultiplier, nEpochs, mutableMapOf()) + + /** + * Number of examples in each batch. A larger batch size means that model parameters are updated + * less frequently, but with lower variance. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun batchSize(): Optional = batchSize.getOptional("batch_size") + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun learningRateMultiplier(): Optional = + learningRateMultiplier.getOptional("learning_rate_multiplier") + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through the + * training dataset. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun nEpochs(): Optional = nEpochs.getOptional("n_epochs") + + /** + * Returns the raw JSON value of [batchSize]. + * + * Unlike [batchSize], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("batch_size") @ExcludeMissing fun _batchSize(): JsonField = batchSize + + /** + * Returns the raw JSON value of [learningRateMultiplier]. + * + * Unlike [learningRateMultiplier], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("learning_rate_multiplier") + @ExcludeMissing + fun _learningRateMultiplier(): JsonField = learningRateMultiplier + + /** + * Returns the raw JSON value of [nEpochs]. + * + * Unlike [nEpochs], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("n_epochs") @ExcludeMissing fun _nEpochs(): JsonField = nEpochs + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SupervisedHyperparameters]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SupervisedHyperparameters]. */ + class Builder internal constructor() { + + private var batchSize: JsonField = JsonMissing.of() + private var learningRateMultiplier: JsonField = JsonMissing.of() + private var nEpochs: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(supervisedHyperparameters: SupervisedHyperparameters) = apply { + batchSize = supervisedHyperparameters.batchSize + learningRateMultiplier = supervisedHyperparameters.learningRateMultiplier + nEpochs = supervisedHyperparameters.nEpochs + additionalProperties = supervisedHyperparameters.additionalProperties.toMutableMap() + } + + /** + * Number of examples in each batch. A larger batch size means that model parameters are + * updated less frequently, but with lower variance. + */ + fun batchSize(batchSize: BatchSize) = batchSize(JsonField.of(batchSize)) + + /** + * Sets [Builder.batchSize] to an arbitrary JSON value. + * + * You should usually call [Builder.batchSize] with a well-typed [BatchSize] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun batchSize(batchSize: JsonField) = apply { this.batchSize = batchSize } + + /** Alias for calling [batchSize] with `BatchSize.ofAuto()`. */ + fun batchSizeAuto() = batchSize(BatchSize.ofAuto()) + + /** Alias for calling [batchSize] with `BatchSize.ofInteger(integer)`. */ + fun batchSize(integer: Long) = batchSize(BatchSize.ofInteger(integer)) + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + */ + fun learningRateMultiplier(learningRateMultiplier: LearningRateMultiplier) = + learningRateMultiplier(JsonField.of(learningRateMultiplier)) + + /** + * Sets [Builder.learningRateMultiplier] to an arbitrary JSON value. + * + * You should usually call [Builder.learningRateMultiplier] with a well-typed + * [LearningRateMultiplier] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun learningRateMultiplier(learningRateMultiplier: JsonField) = + apply { + this.learningRateMultiplier = learningRateMultiplier + } + + /** Alias for calling [learningRateMultiplier] with `LearningRateMultiplier.ofAuto()`. */ + fun learningRateMultiplierAuto() = learningRateMultiplier(LearningRateMultiplier.ofAuto()) + + /** + * Alias for calling [learningRateMultiplier] with + * `LearningRateMultiplier.ofNumber(number)`. + */ + fun learningRateMultiplier(number: Double) = + learningRateMultiplier(LearningRateMultiplier.ofNumber(number)) + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through + * the training dataset. + */ + fun nEpochs(nEpochs: NEpochs) = nEpochs(JsonField.of(nEpochs)) + + /** + * Sets [Builder.nEpochs] to an arbitrary JSON value. + * + * You should usually call [Builder.nEpochs] with a well-typed [NEpochs] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun nEpochs(nEpochs: JsonField) = apply { this.nEpochs = nEpochs } + + /** Alias for calling [nEpochs] with `NEpochs.ofAuto()`. */ + fun nEpochsAuto() = nEpochs(NEpochs.ofAuto()) + + /** Alias for calling [nEpochs] with `NEpochs.ofInteger(integer)`. */ + fun nEpochs(integer: Long) = nEpochs(NEpochs.ofInteger(integer)) + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SupervisedHyperparameters]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SupervisedHyperparameters = + SupervisedHyperparameters( + batchSize, + learningRateMultiplier, + nEpochs, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): SupervisedHyperparameters = apply { + if (validated) { + return@apply + } + + batchSize().ifPresent { it.validate() } + learningRateMultiplier().ifPresent { it.validate() } + nEpochs().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (batchSize.asKnown().getOrNull()?.validity() ?: 0) + + (learningRateMultiplier.asKnown().getOrNull()?.validity() ?: 0) + + (nEpochs.asKnown().getOrNull()?.validity() ?: 0) + + /** + * Number of examples in each batch. A larger batch size means that model parameters are updated + * less frequently, but with lower variance. + */ + @JsonDeserialize(using = BatchSize.Deserializer::class) + @JsonSerialize(using = BatchSize.Serializer::class) + class BatchSize + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): BatchSize = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is BatchSize && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "BatchSize{auto=$auto}" + integer != null -> "BatchSize{integer=$integer}" + _json != null -> "BatchSize{_unknown=$_json}" + else -> throw IllegalStateException("Invalid BatchSize") + } + + companion object { + + @JvmStatic fun ofAuto() = BatchSize(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = BatchSize(integer = integer) + } + + /** + * An interface that defines how to map each variant of [BatchSize] to a value of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [BatchSize] to a value of type [T]. + * + * An instance of [BatchSize] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown BatchSize: $json") + } + } + + internal class Deserializer : BaseDeserializer(BatchSize::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): BatchSize { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { BatchSize(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + BatchSize(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> BatchSize(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(BatchSize::class) { + + override fun serialize( + value: BatchSize, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid BatchSize") + } + } + } + } + + /** + * Scaling factor for the learning rate. A smaller learning rate may be useful to avoid + * overfitting. + */ + @JsonDeserialize(using = LearningRateMultiplier.Deserializer::class) + @JsonSerialize(using = LearningRateMultiplier.Serializer::class) + class LearningRateMultiplier + private constructor( + private val auto: JsonValue? = null, + private val number: Double? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun number(): Optional = Optional.ofNullable(number) + + fun isAuto(): Boolean = auto != null + + fun isNumber(): Boolean = number != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asNumber(): Double = number.getOrThrow("number") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + number != null -> visitor.visitNumber(number) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): LearningRateMultiplier = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitNumber(number: Double) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitNumber(number: Double) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is LearningRateMultiplier && auto == other.auto && number == other.number /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, number) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "LearningRateMultiplier{auto=$auto}" + number != null -> "LearningRateMultiplier{number=$number}" + _json != null -> "LearningRateMultiplier{_unknown=$_json}" + else -> throw IllegalStateException("Invalid LearningRateMultiplier") + } + + companion object { + + @JvmStatic fun ofAuto() = LearningRateMultiplier(auto = JsonValue.from("auto")) + + @JvmStatic fun ofNumber(number: Double) = LearningRateMultiplier(number = number) + } + + /** + * An interface that defines how to map each variant of [LearningRateMultiplier] to a value + * of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitNumber(number: Double): T + + /** + * Maps an unknown variant of [LearningRateMultiplier] to a value of type [T]. + * + * An instance of [LearningRateMultiplier] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK + * is on an older version than the API, then the API may respond with new variants that + * the SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown LearningRateMultiplier: $json") + } + } + + internal class Deserializer : + BaseDeserializer(LearningRateMultiplier::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): LearningRateMultiplier { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { LearningRateMultiplier(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + LearningRateMultiplier(number = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> LearningRateMultiplier(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(LearningRateMultiplier::class) { + + override fun serialize( + value: LearningRateMultiplier, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.number != null -> generator.writeObject(value.number) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid LearningRateMultiplier") + } + } + } + } + + /** + * The number of epochs to train the model for. An epoch refers to one full cycle through the + * training dataset. + */ + @JsonDeserialize(using = NEpochs.Deserializer::class) + @JsonSerialize(using = NEpochs.Serializer::class) + class NEpochs + private constructor( + private val auto: JsonValue? = null, + private val integer: Long? = null, + private val _json: JsonValue? = null, + ) { + + fun auto(): Optional = Optional.ofNullable(auto) + + fun integer(): Optional = Optional.ofNullable(integer) + + fun isAuto(): Boolean = auto != null + + fun isInteger(): Boolean = integer != null + + fun asAuto(): JsonValue = auto.getOrThrow("auto") + + fun asInteger(): Long = integer.getOrThrow("integer") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + auto != null -> visitor.visitAuto(auto) + integer != null -> visitor.visitInteger(integer) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): NEpochs = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) { + auto.let { + if (it != JsonValue.from("auto")) { + throw OpenAIInvalidDataException("'auto' is invalid, received $it") + } + } + } + + override fun visitInteger(integer: Long) {} + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitAuto(auto: JsonValue) = + auto.let { if (it == JsonValue.from("auto")) 1 else 0 } + + override fun visitInteger(integer: Long) = 1 + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is NEpochs && auto == other.auto && integer == other.integer /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(auto, integer) /* spotless:on */ + + override fun toString(): String = + when { + auto != null -> "NEpochs{auto=$auto}" + integer != null -> "NEpochs{integer=$integer}" + _json != null -> "NEpochs{_unknown=$_json}" + else -> throw IllegalStateException("Invalid NEpochs") + } + + companion object { + + @JvmStatic fun ofAuto() = NEpochs(auto = JsonValue.from("auto")) + + @JvmStatic fun ofInteger(integer: Long) = NEpochs(integer = integer) + } + + /** + * An interface that defines how to map each variant of [NEpochs] to a value of type [T]. + */ + interface Visitor { + + fun visitAuto(auto: JsonValue): T + + fun visitInteger(integer: Long): T + + /** + * Maps an unknown variant of [NEpochs] to a value of type [T]. + * + * An instance of [NEpochs] can contain an unknown variant if it was deserialized from + * data that doesn't match any known variant. For example, if the SDK is on an older + * version than the API, then the API may respond with new variants that the SDK is + * unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown NEpochs: $json") + } + } + + internal class Deserializer : BaseDeserializer(NEpochs::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): NEpochs { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef()) + ?.let { NEpochs(auto = it, _json = json) } + ?.takeIf { it.isValid() }, + tryDeserialize(node, jacksonTypeRef())?.let { + NEpochs(integer = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with + // all the possible variants (e.g. deserializing from object). + 0 -> NEpochs(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely + // valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(NEpochs::class) { + + override fun serialize( + value: NEpochs, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.auto != null -> generator.writeObject(value.auto) + value.integer != null -> generator.writeObject(value.integer) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid NEpochs") + } + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is SupervisedHyperparameters && batchSize == other.batchSize && learningRateMultiplier == other.learningRateMultiplier && nEpochs == other.nEpochs && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(batchSize, learningRateMultiplier, nEpochs, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SupervisedHyperparameters{batchSize=$batchSize, learningRateMultiplier=$learningRateMultiplier, nEpochs=$nEpochs, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/SupervisedMethod.kt b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/SupervisedMethod.kt new file mode 100644 index 000000000..e6aa5f128 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/finetuning/methods/SupervisedMethod.kt @@ -0,0 +1,167 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** Configuration for the supervised fine-tuning method. */ +class SupervisedMethod +private constructor( + private val hyperparameters: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("hyperparameters") + @ExcludeMissing + hyperparameters: JsonField = JsonMissing.of() + ) : this(hyperparameters, mutableMapOf()) + + /** + * The hyperparameters used for the fine-tuning job. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun hyperparameters(): Optional = + hyperparameters.getOptional("hyperparameters") + + /** + * Returns the raw JSON value of [hyperparameters]. + * + * Unlike [hyperparameters], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("hyperparameters") + @ExcludeMissing + fun _hyperparameters(): JsonField = hyperparameters + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [SupervisedMethod]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SupervisedMethod]. */ + class Builder internal constructor() { + + private var hyperparameters: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(supervisedMethod: SupervisedMethod) = apply { + hyperparameters = supervisedMethod.hyperparameters + additionalProperties = supervisedMethod.additionalProperties.toMutableMap() + } + + /** The hyperparameters used for the fine-tuning job. */ + fun hyperparameters(hyperparameters: SupervisedHyperparameters) = + hyperparameters(JsonField.of(hyperparameters)) + + /** + * Sets [Builder.hyperparameters] to an arbitrary JSON value. + * + * You should usually call [Builder.hyperparameters] with a well-typed + * [SupervisedHyperparameters] value instead. This method is primarily for setting the field + * to an undocumented or not yet supported value. + */ + fun hyperparameters(hyperparameters: JsonField) = apply { + this.hyperparameters = hyperparameters + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SupervisedMethod]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): SupervisedMethod = + SupervisedMethod(hyperparameters, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + fun validate(): SupervisedMethod = apply { + if (validated) { + return@apply + } + + hyperparameters().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = (hyperparameters.asKnown().getOrNull()?.validity() ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is SupervisedMethod && hyperparameters == other.hyperparameters && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(hyperparameters, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SupervisedMethod{hyperparameters=$hyperparameters, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalLabelModelGrader.kt b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/LabelModelGrader.kt similarity index 97% rename from openai-java-core/src/main/kotlin/com/openai/models/evals/EvalLabelModelGrader.kt rename to openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/LabelModelGrader.kt index 7576d0c9f..e29ecd157 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalLabelModelGrader.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/LabelModelGrader.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.openai.models.evals +package com.openai.models.graders.gradermodels import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -33,7 +33,7 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** A LabelModelGrader object which uses a model to assign labels to each item in the evaluation. */ -class EvalLabelModelGrader +class LabelModelGrader private constructor( private val input: JsonField>, private val labels: JsonField>, @@ -159,7 +159,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [EvalLabelModelGrader]. + * Returns a mutable builder for constructing an instance of [LabelModelGrader]. * * The following fields are required: * ```java @@ -173,7 +173,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [EvalLabelModelGrader]. */ + /** A builder for [LabelModelGrader]. */ class Builder internal constructor() { private var input: JsonField>? = null @@ -185,14 +185,14 @@ private constructor( private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(evalLabelModelGrader: EvalLabelModelGrader) = apply { - input = evalLabelModelGrader.input.map { it.toMutableList() } - labels = evalLabelModelGrader.labels.map { it.toMutableList() } - model = evalLabelModelGrader.model - name = evalLabelModelGrader.name - passingLabels = evalLabelModelGrader.passingLabels.map { it.toMutableList() } - type = evalLabelModelGrader.type - additionalProperties = evalLabelModelGrader.additionalProperties.toMutableMap() + internal fun from(labelModelGrader: LabelModelGrader) = apply { + input = labelModelGrader.input.map { it.toMutableList() } + labels = labelModelGrader.labels.map { it.toMutableList() } + model = labelModelGrader.model + name = labelModelGrader.name + passingLabels = labelModelGrader.passingLabels.map { it.toMutableList() } + type = labelModelGrader.type + additionalProperties = labelModelGrader.additionalProperties.toMutableMap() } fun input(input: List) = input(JsonField.of(input)) @@ -328,7 +328,7 @@ private constructor( } /** - * Returns an immutable instance of [EvalLabelModelGrader]. + * Returns an immutable instance of [LabelModelGrader]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -343,8 +343,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): EvalLabelModelGrader = - EvalLabelModelGrader( + fun build(): LabelModelGrader = + LabelModelGrader( checkRequired("input", input).map { it.toImmutable() }, checkRequired("labels", labels).map { it.toImmutable() }, checkRequired("model", model), @@ -357,7 +357,7 @@ private constructor( private var validated: Boolean = false - fun validate(): EvalLabelModelGrader = apply { + fun validate(): LabelModelGrader = apply { if (validated) { return@apply } @@ -1335,7 +1335,7 @@ private constructor( return true } - return /* spotless:off */ other is EvalLabelModelGrader && input == other.input && labels == other.labels && model == other.model && name == other.name && passingLabels == other.passingLabels && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is LabelModelGrader && input == other.input && labels == other.labels && model == other.model && name == other.name && passingLabels == other.passingLabels && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ @@ -1345,5 +1345,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "EvalLabelModelGrader{input=$input, labels=$labels, model=$model, name=$name, passingLabels=$passingLabels, type=$type, additionalProperties=$additionalProperties}" + "LabelModelGrader{input=$input, labels=$labels, model=$model, name=$name, passingLabels=$passingLabels, type=$type, additionalProperties=$additionalProperties}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/MultiGrader.kt b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/MultiGrader.kt new file mode 100644 index 000000000..8b9501898 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/MultiGrader.kt @@ -0,0 +1,391 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.checkRequired +import com.openai.core.toImmutable +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import kotlin.jvm.optionals.getOrNull + +/** A MultiGrader object combines the output of multiple graders to produce a single score. */ +class MultiGrader +private constructor( + private val calculateOutput: JsonField, + private val graders: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("calculate_output") + @ExcludeMissing + calculateOutput: JsonField = JsonMissing.of(), + @JsonProperty("graders") @ExcludeMissing graders: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + ) : this(calculateOutput, graders, name, type, mutableMapOf()) + + /** + * A formula to calculate the output based on grader results. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun calculateOutput(): String = calculateOutput.getRequired("calculate_output") + + /** + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun graders(): Graders = graders.getRequired("graders") + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun name(): String = name.getRequired("name") + + /** + * The type of grader. + * + * Expected to always return the following: + * ```java + * JsonValue.from("multi") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server responded + * with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * Returns the raw JSON value of [calculateOutput]. + * + * Unlike [calculateOutput], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("calculate_output") + @ExcludeMissing + fun _calculateOutput(): JsonField = calculateOutput + + /** + * Returns the raw JSON value of [graders]. + * + * Unlike [graders], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("graders") @ExcludeMissing fun _graders(): JsonField = graders + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [MultiGrader]. + * + * The following fields are required: + * ```java + * .calculateOutput() + * .graders() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [MultiGrader]. */ + class Builder internal constructor() { + + private var calculateOutput: JsonField? = null + private var graders: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("multi") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(multiGrader: MultiGrader) = apply { + calculateOutput = multiGrader.calculateOutput + graders = multiGrader.graders + name = multiGrader.name + type = multiGrader.type + additionalProperties = multiGrader.additionalProperties.toMutableMap() + } + + /** A formula to calculate the output based on grader results. */ + fun calculateOutput(calculateOutput: String) = + calculateOutput(JsonField.of(calculateOutput)) + + /** + * Sets [Builder.calculateOutput] to an arbitrary JSON value. + * + * You should usually call [Builder.calculateOutput] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun calculateOutput(calculateOutput: JsonField) = apply { + this.calculateOutput = calculateOutput + } + + fun graders(graders: Graders) = graders(JsonField.of(graders)) + + /** + * Sets [Builder.graders] to an arbitrary JSON value. + * + * You should usually call [Builder.graders] with a well-typed [Graders] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun graders(graders: JsonField) = apply { this.graders = graders } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("multi") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [MultiGrader]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .calculateOutput() + * .graders() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): MultiGrader = + MultiGrader( + checkRequired("calculateOutput", calculateOutput), + checkRequired("graders", graders), + checkRequired("name", name), + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): MultiGrader = apply { + if (validated) { + return@apply + } + + calculateOutput() + graders().validate() + name() + _type().let { + if (it != JsonValue.from("multi")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (calculateOutput.asKnown().isPresent) 1 else 0) + + (graders.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("multi")) 1 else 0 } + + class Graders + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Graders]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Graders]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(graders: Graders) = apply { + additionalProperties = graders.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Graders]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Graders = Graders(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + fun validate(): Graders = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + additionalProperties.count { (_, value) -> !value.isNull() && !value.isMissing() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Graders && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = "Graders{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is MultiGrader && calculateOutput == other.calculateOutput && graders == other.graders && name == other.name && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(calculateOutput, graders, name, type, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "MultiGrader{calculateOutput=$calculateOutput, graders=$graders, name=$name, type=$type, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/PythonGrader.kt b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/PythonGrader.kt new file mode 100644 index 000000000..6aef3d56b --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/PythonGrader.kt @@ -0,0 +1,282 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.checkRequired +import com.openai.errors.OpenAIInvalidDataException +import java.util.Collections +import java.util.Objects +import java.util.Optional + +/** A PythonGrader object that runs a python script on the input. */ +class PythonGrader +private constructor( + private val name: JsonField, + private val source: JsonField, + private val type: JsonValue, + private val imageTag: JsonField, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("image_tag") @ExcludeMissing imageTag: JsonField = JsonMissing.of(), + ) : this(name, source, type, imageTag, mutableMapOf()) + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun name(): String = name.getRequired("name") + + /** + * The source code of the python script. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun source(): String = source.getRequired("source") + + /** + * The object type, which is always `python`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("python") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server responded + * with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The image tag to use for the python script. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun imageTag(): Optional = imageTag.getOptional("image_tag") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [source]. + * + * Unlike [source], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("source") @ExcludeMissing fun _source(): JsonField = source + + /** + * Returns the raw JSON value of [imageTag]. + * + * Unlike [imageTag], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("image_tag") @ExcludeMissing fun _imageTag(): JsonField = imageTag + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [PythonGrader]. + * + * The following fields are required: + * ```java + * .name() + * .source() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PythonGrader]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var source: JsonField? = null + private var type: JsonValue = JsonValue.from("python") + private var imageTag: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(pythonGrader: PythonGrader) = apply { + name = pythonGrader.name + source = pythonGrader.source + type = pythonGrader.type + imageTag = pythonGrader.imageTag + additionalProperties = pythonGrader.additionalProperties.toMutableMap() + } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** The source code of the python script. */ + fun source(source: String) = source(JsonField.of(source)) + + /** + * Sets [Builder.source] to an arbitrary JSON value. + * + * You should usually call [Builder.source] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun source(source: JsonField) = apply { this.source = source } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("python") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The image tag to use for the python script. */ + fun imageTag(imageTag: String) = imageTag(JsonField.of(imageTag)) + + /** + * Sets [Builder.imageTag] to an arbitrary JSON value. + * + * You should usually call [Builder.imageTag] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun imageTag(imageTag: JsonField) = apply { this.imageTag = imageTag } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PythonGrader]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .source() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): PythonGrader = + PythonGrader( + checkRequired("name", name), + checkRequired("source", source), + type, + imageTag, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): PythonGrader = apply { + if (validated) { + return@apply + } + + name() + source() + _type().let { + if (it != JsonValue.from("python")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + imageTag() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (if (source.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("python")) 1 else 0 } + + (if (imageTag.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is PythonGrader && name == other.name && source == other.source && type == other.type && imageTag == other.imageTag && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(name, source, type, imageTag, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PythonGrader{name=$name, source=$source, type=$type, imageTag=$imageTag, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/ScoreModelGrader.kt b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/ScoreModelGrader.kt new file mode 100644 index 000000000..b6dc3c821 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/ScoreModelGrader.kt @@ -0,0 +1,1313 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.BaseDeserializer +import com.openai.core.BaseSerializer +import com.openai.core.Enum +import com.openai.core.ExcludeMissing +import com.openai.core.JsonField +import com.openai.core.JsonMissing +import com.openai.core.JsonValue +import com.openai.core.allMaxBy +import com.openai.core.checkKnown +import com.openai.core.checkRequired +import com.openai.core.getOrThrow +import com.openai.core.toImmutable +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.responses.ResponseInputText +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** A ScoreModelGrader object that uses a model to assign a score to the input. */ +class ScoreModelGrader +private constructor( + private val input: JsonField>, + private val model: JsonField, + private val name: JsonField, + private val type: JsonValue, + private val range: JsonField>, + private val samplingParams: JsonValue, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("input") @ExcludeMissing input: JsonField> = JsonMissing.of(), + @JsonProperty("model") @ExcludeMissing model: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + @JsonProperty("range") @ExcludeMissing range: JsonField> = JsonMissing.of(), + @JsonProperty("sampling_params") + @ExcludeMissing + samplingParams: JsonValue = JsonMissing.of(), + ) : this(input, model, name, type, range, samplingParams, mutableMapOf()) + + /** + * The input text. This may include template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun input(): List = input.getRequired("input") + + /** + * The model to use for the evaluation. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun model(): String = model.getRequired("model") + + /** + * The name of the grader. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun name(): String = name.getRequired("name") + + /** + * The object type, which is always `score_model`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server responded + * with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * The range of the score. Defaults to `[0, 1]`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun range(): Optional> = range.getOptional("range") + + /** The sampling parameters for the model. */ + @JsonProperty("sampling_params") + @ExcludeMissing + fun _samplingParams(): JsonValue = samplingParams + + /** + * Returns the raw JSON value of [input]. + * + * Unlike [input], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("input") @ExcludeMissing fun _input(): JsonField> = input + + /** + * Returns the raw JSON value of [model]. + * + * Unlike [model], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("model") @ExcludeMissing fun _model(): JsonField = model + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [range]. + * + * Unlike [range], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("range") @ExcludeMissing fun _range(): JsonField> = range + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [ScoreModelGrader]. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [ScoreModelGrader]. */ + class Builder internal constructor() { + + private var input: JsonField>? = null + private var model: JsonField? = null + private var name: JsonField? = null + private var type: JsonValue = JsonValue.from("score_model") + private var range: JsonField>? = null + private var samplingParams: JsonValue = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(scoreModelGrader: ScoreModelGrader) = apply { + input = scoreModelGrader.input.map { it.toMutableList() } + model = scoreModelGrader.model + name = scoreModelGrader.name + type = scoreModelGrader.type + range = scoreModelGrader.range.map { it.toMutableList() } + samplingParams = scoreModelGrader.samplingParams + additionalProperties = scoreModelGrader.additionalProperties.toMutableMap() + } + + /** The input text. This may include template strings. */ + fun input(input: List) = input(JsonField.of(input)) + + /** + * Sets [Builder.input] to an arbitrary JSON value. + * + * You should usually call [Builder.input] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun input(input: JsonField>) = apply { + this.input = input.map { it.toMutableList() } + } + + /** + * Adds a single [Input] to [Builder.input]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addInput(input: Input) = apply { + this.input = + (this.input ?: JsonField.of(mutableListOf())).also { + checkKnown("input", it).add(input) + } + } + + /** The model to use for the evaluation. */ + fun model(model: String) = model(JsonField.of(model)) + + /** + * Sets [Builder.model] to an arbitrary JSON value. + * + * You should usually call [Builder.model] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun model(model: JsonField) = apply { this.model = model } + + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("score_model") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + /** The range of the score. Defaults to `[0, 1]`. */ + fun range(range: List) = range(JsonField.of(range)) + + /** + * Sets [Builder.range] to an arbitrary JSON value. + * + * You should usually call [Builder.range] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun range(range: JsonField>) = apply { + this.range = range.map { it.toMutableList() } + } + + /** + * Adds a single [Double] to [Builder.range]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRange(range: Double) = apply { + this.range = + (this.range ?: JsonField.of(mutableListOf())).also { + checkKnown("range", it).add(range) + } + } + + /** The sampling parameters for the model. */ + fun samplingParams(samplingParams: JsonValue) = apply { + this.samplingParams = samplingParams + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [ScoreModelGrader]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .name() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): ScoreModelGrader = + ScoreModelGrader( + checkRequired("input", input).map { it.toImmutable() }, + checkRequired("model", model), + checkRequired("name", name), + type, + (range ?: JsonMissing.of()).map { it.toImmutable() }, + samplingParams, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): ScoreModelGrader = apply { + if (validated) { + return@apply + } + + input().forEach { it.validate() } + model() + name() + _type().let { + if (it != JsonValue.from("score_model")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + range() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (input.asKnown().getOrNull()?.sumOf { it.validity().toInt() } ?: 0) + + (if (model.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("score_model")) 1 else 0 } + + (range.asKnown().getOrNull()?.size ?: 0) + + /** + * A message input to the model with a role indicating instruction following hierarchy. + * Instructions given with the `developer` or `system` role take precedence over instructions + * given with the `user` role. Messages with the `assistant` role are presumed to have been + * generated by the model in previous interactions. + */ + class Input + private constructor( + private val content: JsonField, + private val role: JsonField, + private val type: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("content") @ExcludeMissing content: JsonField = JsonMissing.of(), + @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), + ) : this(content, role, type, mutableMapOf()) + + /** + * Text inputs to the model - can contain template strings. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun content(): Content = content.getRequired("content") + + /** + * The role of the message input. One of `user`, `assistant`, `system`, or `developer`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun role(): Role = role.getRequired("role") + + /** + * The type of the message input. Always `message`. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the + * server responded with an unexpected value). + */ + fun type(): Optional = type.getOptional("type") + + /** + * Returns the raw JSON value of [content]. + * + * Unlike [content], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("content") @ExcludeMissing fun _content(): JsonField = content + + /** + * Returns the raw JSON value of [role]. + * + * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role + + /** + * Returns the raw JSON value of [type]. + * + * Unlike [type], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonField = type + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Input]. + * + * The following fields are required: + * ```java + * .content() + * .role() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Input]. */ + class Builder internal constructor() { + + private var content: JsonField? = null + private var role: JsonField? = null + private var type: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(input: Input) = apply { + content = input.content + role = input.role + type = input.type + additionalProperties = input.additionalProperties.toMutableMap() + } + + /** Text inputs to the model - can contain template strings. */ + fun content(content: Content) = content(JsonField.of(content)) + + /** + * Sets [Builder.content] to an arbitrary JSON value. + * + * You should usually call [Builder.content] with a well-typed [Content] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun content(content: JsonField) = apply { this.content = content } + + /** Alias for calling [content] with `Content.ofTextInput(textInput)`. */ + fun content(textInput: String) = content(Content.ofTextInput(textInput)) + + /** + * Alias for calling [content] with `Content.ofResponseInputText(responseInputText)`. + */ + fun content(responseInputText: ResponseInputText) = + content(Content.ofResponseInputText(responseInputText)) + + /** Alias for calling [content] with `Content.ofOutputText(outputText)`. */ + fun content(outputText: Content.OutputText) = content(Content.ofOutputText(outputText)) + + /** + * The role of the message input. One of `user`, `assistant`, `system`, or `developer`. + */ + fun role(role: Role) = role(JsonField.of(role)) + + /** + * Sets [Builder.role] to an arbitrary JSON value. + * + * You should usually call [Builder.role] with a well-typed [Role] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun role(role: JsonField) = apply { this.role = role } + + /** The type of the message input. Always `message`. */ + fun type(type: Type) = type(JsonField.of(type)) + + /** + * Sets [Builder.type] to an arbitrary JSON value. + * + * You should usually call [Builder.type] with a well-typed [Type] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun type(type: JsonField) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Input]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .content() + * .role() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Input = + Input( + checkRequired("content", content), + checkRequired("role", role), + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): Input = apply { + if (validated) { + return@apply + } + + content().validate() + role().validate() + type().ifPresent { it.validate() } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (content.asKnown().getOrNull()?.validity() ?: 0) + + (role.asKnown().getOrNull()?.validity() ?: 0) + + (type.asKnown().getOrNull()?.validity() ?: 0) + + /** Text inputs to the model - can contain template strings. */ + @JsonDeserialize(using = Content.Deserializer::class) + @JsonSerialize(using = Content.Serializer::class) + class Content + private constructor( + private val textInput: String? = null, + private val responseInputText: ResponseInputText? = null, + private val outputText: OutputText? = null, + private val _json: JsonValue? = null, + ) { + + /** A text input to the model. */ + fun textInput(): Optional = Optional.ofNullable(textInput) + + /** A text input to the model. */ + fun responseInputText(): Optional = + Optional.ofNullable(responseInputText) + + /** A text output from the model. */ + fun outputText(): Optional = Optional.ofNullable(outputText) + + fun isTextInput(): Boolean = textInput != null + + fun isResponseInputText(): Boolean = responseInputText != null + + fun isOutputText(): Boolean = outputText != null + + /** A text input to the model. */ + fun asTextInput(): String = textInput.getOrThrow("textInput") + + /** A text input to the model. */ + fun asResponseInputText(): ResponseInputText = + responseInputText.getOrThrow("responseInputText") + + /** A text output from the model. */ + fun asOutputText(): OutputText = outputText.getOrThrow("outputText") + + fun _json(): Optional = Optional.ofNullable(_json) + + fun accept(visitor: Visitor): T = + when { + textInput != null -> visitor.visitTextInput(textInput) + responseInputText != null -> visitor.visitResponseInputText(responseInputText) + outputText != null -> visitor.visitOutputText(outputText) + else -> visitor.unknown(_json) + } + + private var validated: Boolean = false + + fun validate(): Content = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitTextInput(textInput: String) {} + + override fun visitResponseInputText(responseInputText: ResponseInputText) { + responseInputText.validate() + } + + override fun visitOutputText(outputText: OutputText) { + outputText.validate() + } + } + ) + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + accept( + object : Visitor { + override fun visitTextInput(textInput: String) = 1 + + override fun visitResponseInputText(responseInputText: ResponseInputText) = + responseInputText.validity() + + override fun visitOutputText(outputText: OutputText) = outputText.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Content && textInput == other.textInput && responseInputText == other.responseInputText && outputText == other.outputText /* spotless:on */ + } + + override fun hashCode(): Int = /* spotless:off */ Objects.hash(textInput, responseInputText, outputText) /* spotless:on */ + + override fun toString(): String = + when { + textInput != null -> "Content{textInput=$textInput}" + responseInputText != null -> "Content{responseInputText=$responseInputText}" + outputText != null -> "Content{outputText=$outputText}" + _json != null -> "Content{_unknown=$_json}" + else -> throw IllegalStateException("Invalid Content") + } + + companion object { + + /** A text input to the model. */ + @JvmStatic fun ofTextInput(textInput: String) = Content(textInput = textInput) + + /** A text input to the model. */ + @JvmStatic + fun ofResponseInputText(responseInputText: ResponseInputText) = + Content(responseInputText = responseInputText) + + /** A text output from the model. */ + @JvmStatic + fun ofOutputText(outputText: OutputText) = Content(outputText = outputText) + } + + /** + * An interface that defines how to map each variant of [Content] to a value of type + * [T]. + */ + interface Visitor { + + /** A text input to the model. */ + fun visitTextInput(textInput: String): T + + /** A text input to the model. */ + fun visitResponseInputText(responseInputText: ResponseInputText): T + + /** A text output from the model. */ + fun visitOutputText(outputText: OutputText): T + + /** + * Maps an unknown variant of [Content] to a value of type [T]. + * + * An instance of [Content] can contain an unknown variant if it was deserialized + * from data that doesn't match any known variant. For example, if the SDK is on an + * older version than the API, then the API may respond with new variants that the + * SDK is unaware of. + * + * @throws OpenAIInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown Content: $json") + } + } + + internal class Deserializer : BaseDeserializer(Content::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): Content { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + Content(responseInputText = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Content(outputText = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + Content(textInput = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible + // with all the possible variants (e.g. deserializing from array). + 0 -> Content(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the + // first completely valid match, or simply the first match if none are + // completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : BaseSerializer(Content::class) { + + override fun serialize( + value: Content, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.textInput != null -> generator.writeObject(value.textInput) + value.responseInputText != null -> + generator.writeObject(value.responseInputText) + value.outputText != null -> generator.writeObject(value.outputText) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid Content") + } + } + } + + /** A text output from the model. */ + class OutputText + private constructor( + private val text: JsonField, + private val type: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("text") + @ExcludeMissing + text: JsonField = JsonMissing.of(), + @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), + ) : this(text, type, mutableMapOf()) + + /** + * The text output from the model. + * + * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun text(): String = text.getRequired("text") + + /** + * The type of the output text. Always `output_text`. + * + * Expected to always return the following: + * ```java + * JsonValue.from("output_text") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [OutputText]. + * + * The following fields are required: + * ```java + * .text() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [OutputText]. */ + class Builder internal constructor() { + + private var text: JsonField? = null + private var type: JsonValue = JsonValue.from("output_text") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(outputText: OutputText) = apply { + text = outputText.text + type = outputText.type + additionalProperties = outputText.additionalProperties.toMutableMap() + } + + /** The text output from the model. */ + fun text(text: String) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun text(text: JsonField) = apply { this.text = text } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to + * the following: + * ```java + * JsonValue.from("output_text") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun type(type: JsonValue) = apply { this.type = type } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [OutputText]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .text() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): OutputText = + OutputText( + checkRequired("text", text), + type, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + fun validate(): OutputText = apply { + if (validated) { + return@apply + } + + text() + _type().let { + if (it != JsonValue.from("output_text")) { + throw OpenAIInvalidDataException("'type' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (text.asKnown().isPresent) 1 else 0) + + type.let { if (it == JsonValue.from("output_text")) 1 else 0 } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is OutputText && text == other.text && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(text, type, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "OutputText{text=$text, type=$type, additionalProperties=$additionalProperties}" + } + } + + /** The role of the message input. One of `user`, `assistant`, `system`, or `developer`. */ + class Role @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val USER = of("user") + + @JvmField val ASSISTANT = of("assistant") + + @JvmField val SYSTEM = of("system") + + @JvmField val DEVELOPER = of("developer") + + @JvmStatic fun of(value: String) = Role(JsonField.of(value)) + } + + /** An enum containing [Role]'s known values. */ + enum class Known { + USER, + ASSISTANT, + SYSTEM, + DEVELOPER, + } + + /** + * An enum containing [Role]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Role] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + USER, + ASSISTANT, + SYSTEM, + DEVELOPER, + /** An enum member indicating that [Role] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + USER -> Value.USER + ASSISTANT -> Value.ASSISTANT + SYSTEM -> Value.SYSTEM + DEVELOPER -> Value.DEVELOPER + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + USER -> Known.USER + ASSISTANT -> Known.ASSISTANT + SYSTEM -> Known.SYSTEM + DEVELOPER -> Known.DEVELOPER + else -> throw OpenAIInvalidDataException("Unknown Role: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + OpenAIInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Role = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Role && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + /** The type of the message input. Always `message`. */ + class Type @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val MESSAGE = of("message") + + @JvmStatic fun of(value: String) = Type(JsonField.of(value)) + } + + /** An enum containing [Type]'s known values. */ + enum class Known { + MESSAGE + } + + /** + * An enum containing [Type]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Type] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + MESSAGE, + /** An enum member indicating that [Type] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + MESSAGE -> Value.MESSAGE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws OpenAIInvalidDataException if this class instance's value is a not a known + * member. + */ + fun known(): Known = + when (this) { + MESSAGE -> Known.MESSAGE + else -> throw OpenAIInvalidDataException("Unknown Type: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws OpenAIInvalidDataException if this class instance's value does not have the + * expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + OpenAIInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + fun validate(): Type = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Type && value == other.value /* spotless:on */ + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is Input && content == other.content && role == other.role && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(content, role, type, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Input{content=$content, role=$role, type=$type, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return /* spotless:off */ other is ScoreModelGrader && input == other.input && model == other.model && name == other.name && type == other.type && range == other.range && samplingParams == other.samplingParams && additionalProperties == other.additionalProperties /* spotless:on */ + } + + /* spotless:off */ + private val hashCode: Int by lazy { Objects.hash(input, model, name, type, range, samplingParams, additionalProperties) } + /* spotless:on */ + + override fun hashCode(): Int = hashCode + + override fun toString() = + "ScoreModelGrader{input=$input, model=$model, name=$name, type=$type, range=$range, samplingParams=$samplingParams, additionalProperties=$additionalProperties}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalStringCheckGrader.kt b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/StringCheckGrader.kt similarity index 92% rename from openai-java-core/src/main/kotlin/com/openai/models/evals/EvalStringCheckGrader.kt rename to openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/StringCheckGrader.kt index e1279a149..34bf92168 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalStringCheckGrader.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/StringCheckGrader.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.openai.models.evals +package com.openai.models.graders.gradermodels import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -21,7 +21,7 @@ import kotlin.jvm.optionals.getOrNull * A StringCheckGrader object that performs a string comparison between input and reference using a * specified operation. */ -class EvalStringCheckGrader +class StringCheckGrader private constructor( private val input: JsonField, private val name: JsonField, @@ -130,7 +130,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [EvalStringCheckGrader]. + * Returns a mutable builder for constructing an instance of [StringCheckGrader]. * * The following fields are required: * ```java @@ -143,7 +143,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [EvalStringCheckGrader]. */ + /** A builder for [StringCheckGrader]. */ class Builder internal constructor() { private var input: JsonField? = null @@ -154,13 +154,13 @@ private constructor( private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(evalStringCheckGrader: EvalStringCheckGrader) = apply { - input = evalStringCheckGrader.input - name = evalStringCheckGrader.name - operation = evalStringCheckGrader.operation - reference = evalStringCheckGrader.reference - type = evalStringCheckGrader.type - additionalProperties = evalStringCheckGrader.additionalProperties.toMutableMap() + internal fun from(stringCheckGrader: StringCheckGrader) = apply { + input = stringCheckGrader.input + name = stringCheckGrader.name + operation = stringCheckGrader.operation + reference = stringCheckGrader.reference + type = stringCheckGrader.type + additionalProperties = stringCheckGrader.additionalProperties.toMutableMap() } /** The input text. This may include template strings. */ @@ -243,7 +243,7 @@ private constructor( } /** - * Returns an immutable instance of [EvalStringCheckGrader]. + * Returns an immutable instance of [StringCheckGrader]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -257,8 +257,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): EvalStringCheckGrader = - EvalStringCheckGrader( + fun build(): StringCheckGrader = + StringCheckGrader( checkRequired("input", input), checkRequired("name", name), checkRequired("operation", operation), @@ -270,7 +270,7 @@ private constructor( private var validated: Boolean = false - fun validate(): EvalStringCheckGrader = apply { + fun validate(): StringCheckGrader = apply { if (validated) { return@apply } @@ -453,7 +453,7 @@ private constructor( return true } - return /* spotless:off */ other is EvalStringCheckGrader && input == other.input && name == other.name && operation == other.operation && reference == other.reference && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is StringCheckGrader && input == other.input && name == other.name && operation == other.operation && reference == other.reference && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ @@ -463,5 +463,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "EvalStringCheckGrader{input=$input, name=$name, operation=$operation, reference=$reference, type=$type, additionalProperties=$additionalProperties}" + "StringCheckGrader{input=$input, name=$name, operation=$operation, reference=$reference, type=$type, additionalProperties=$additionalProperties}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalTextSimilarityGrader.kt b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/TextSimilarityGrader.kt similarity index 82% rename from openai-java-core/src/main/kotlin/com/openai/models/evals/EvalTextSimilarityGrader.kt rename to openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/TextSimilarityGrader.kt index 271cc2c21..a72392d4d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/evals/EvalTextSimilarityGrader.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/graders/gradermodels/TextSimilarityGrader.kt @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. -package com.openai.models.evals +package com.openai.models.graders.gradermodels import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter @@ -15,18 +15,16 @@ import com.openai.core.checkRequired import com.openai.errors.OpenAIInvalidDataException import java.util.Collections import java.util.Objects -import java.util.Optional import kotlin.jvm.optionals.getOrNull /** A TextSimilarityGrader object which grades text based on similarity metrics. */ -class EvalTextSimilarityGrader +class TextSimilarityGrader private constructor( private val evaluationMetric: JsonField, private val input: JsonField, - private val passThreshold: JsonField, + private val name: JsonField, private val reference: JsonField, private val type: JsonValue, - private val name: JsonField, private val additionalProperties: MutableMap, ) { @@ -36,13 +34,10 @@ private constructor( @ExcludeMissing evaluationMetric: JsonField = JsonMissing.of(), @JsonProperty("input") @ExcludeMissing input: JsonField = JsonMissing.of(), - @JsonProperty("pass_threshold") - @ExcludeMissing - passThreshold: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), @JsonProperty("reference") @ExcludeMissing reference: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonValue = JsonMissing.of(), - @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), - ) : this(evaluationMetric, input, passThreshold, reference, type, name, mutableMapOf()) + ) : this(evaluationMetric, input, name, reference, type, mutableMapOf()) /** * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, @@ -62,12 +57,12 @@ private constructor( fun input(): String = input.getRequired("input") /** - * A float score where a value greater than or equal indicates a passing grade. + * The name of the grader. * * @throws OpenAIInvalidDataException if the JSON field has an unexpected type or is * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun passThreshold(): Double = passThreshold.getRequired("pass_threshold") + fun name(): String = name.getRequired("name") /** * The text being graded against. @@ -90,14 +85,6 @@ private constructor( */ @JsonProperty("type") @ExcludeMissing fun _type(): JsonValue = type - /** - * The name of the grader. - * - * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the - * server responded with an unexpected value). - */ - fun name(): Optional = name.getOptional("name") - /** * Returns the raw JSON value of [evaluationMetric]. * @@ -116,13 +103,11 @@ private constructor( @JsonProperty("input") @ExcludeMissing fun _input(): JsonField = input /** - * Returns the raw JSON value of [passThreshold]. + * Returns the raw JSON value of [name]. * - * Unlike [passThreshold], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("pass_threshold") - @ExcludeMissing - fun _passThreshold(): JsonField = passThreshold + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name /** * Returns the raw JSON value of [reference]. @@ -131,13 +116,6 @@ private constructor( */ @JsonProperty("reference") @ExcludeMissing fun _reference(): JsonField = reference - /** - * Returns the raw JSON value of [name]. - * - * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name - @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -153,39 +131,37 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of [EvalTextSimilarityGrader]. + * Returns a mutable builder for constructing an instance of [TextSimilarityGrader]. * * The following fields are required: * ```java * .evaluationMetric() * .input() - * .passThreshold() + * .name() * .reference() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [EvalTextSimilarityGrader]. */ + /** A builder for [TextSimilarityGrader]. */ class Builder internal constructor() { private var evaluationMetric: JsonField? = null private var input: JsonField? = null - private var passThreshold: JsonField? = null + private var name: JsonField? = null private var reference: JsonField? = null private var type: JsonValue = JsonValue.from("text_similarity") - private var name: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(evalTextSimilarityGrader: EvalTextSimilarityGrader) = apply { - evaluationMetric = evalTextSimilarityGrader.evaluationMetric - input = evalTextSimilarityGrader.input - passThreshold = evalTextSimilarityGrader.passThreshold - reference = evalTextSimilarityGrader.reference - type = evalTextSimilarityGrader.type - name = evalTextSimilarityGrader.name - additionalProperties = evalTextSimilarityGrader.additionalProperties.toMutableMap() + internal fun from(textSimilarityGrader: TextSimilarityGrader) = apply { + evaluationMetric = textSimilarityGrader.evaluationMetric + input = textSimilarityGrader.input + name = textSimilarityGrader.name + reference = textSimilarityGrader.reference + type = textSimilarityGrader.type + additionalProperties = textSimilarityGrader.additionalProperties.toMutableMap() } /** @@ -217,19 +193,16 @@ private constructor( */ fun input(input: JsonField) = apply { this.input = input } - /** A float score where a value greater than or equal indicates a passing grade. */ - fun passThreshold(passThreshold: Double) = passThreshold(JsonField.of(passThreshold)) + /** The name of the grader. */ + fun name(name: String) = name(JsonField.of(name)) /** - * Sets [Builder.passThreshold] to an arbitrary JSON value. + * Sets [Builder.name] to an arbitrary JSON value. * - * You should usually call [Builder.passThreshold] with a well-typed [Double] value instead. - * This method is primarily for setting the field to an undocumented or not yet supported - * value. + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun passThreshold(passThreshold: JsonField) = apply { - this.passThreshold = passThreshold - } + fun name(name: JsonField) = apply { this.name = name } /** The text being graded against. */ fun reference(reference: String) = reference(JsonField.of(reference)) @@ -257,17 +230,6 @@ private constructor( */ fun type(type: JsonValue) = apply { this.type = type } - /** The name of the grader. */ - fun name(name: String) = name(JsonField.of(name)) - - /** - * Sets [Builder.name] to an arbitrary JSON value. - * - * You should usually call [Builder.name] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. - */ - fun name(name: JsonField) = apply { this.name = name } - fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -288,7 +250,7 @@ private constructor( } /** - * Returns an immutable instance of [EvalTextSimilarityGrader]. + * Returns an immutable instance of [TextSimilarityGrader]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -296,41 +258,39 @@ private constructor( * ```java * .evaluationMetric() * .input() - * .passThreshold() + * .name() * .reference() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): EvalTextSimilarityGrader = - EvalTextSimilarityGrader( + fun build(): TextSimilarityGrader = + TextSimilarityGrader( checkRequired("evaluationMetric", evaluationMetric), checkRequired("input", input), - checkRequired("passThreshold", passThreshold), + checkRequired("name", name), checkRequired("reference", reference), type, - name, additionalProperties.toMutableMap(), ) } private var validated: Boolean = false - fun validate(): EvalTextSimilarityGrader = apply { + fun validate(): TextSimilarityGrader = apply { if (validated) { return@apply } evaluationMetric().validate() input() - passThreshold() + name() reference() _type().let { if (it != JsonValue.from("text_similarity")) { throw OpenAIInvalidDataException("'type' is invalid, received $it") } } - name() validated = true } @@ -351,10 +311,9 @@ private constructor( internal fun validity(): Int = (evaluationMetric.asKnown().getOrNull()?.validity() ?: 0) + (if (input.asKnown().isPresent) 1 else 0) + - (if (passThreshold.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + (if (reference.asKnown().isPresent) 1 else 0) + - type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } + - (if (name.asKnown().isPresent) 1 else 0) + type.let { if (it == JsonValue.from("text_similarity")) 1 else 0 } /** * The evaluation metric to use. One of `fuzzy_match`, `bleu`, `gleu`, `meteor`, `rouge_1`, @@ -542,15 +501,15 @@ private constructor( return true } - return /* spotless:off */ other is EvalTextSimilarityGrader && evaluationMetric == other.evaluationMetric && input == other.input && passThreshold == other.passThreshold && reference == other.reference && type == other.type && name == other.name && additionalProperties == other.additionalProperties /* spotless:on */ + return /* spotless:off */ other is TextSimilarityGrader && evaluationMetric == other.evaluationMetric && input == other.input && name == other.name && reference == other.reference && type == other.type && additionalProperties == other.additionalProperties /* spotless:on */ } /* spotless:off */ - private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, passThreshold, reference, type, name, additionalProperties) } + private val hashCode: Int by lazy { Objects.hash(evaluationMetric, input, name, reference, type, additionalProperties) } /* spotless:on */ override fun hashCode(): Int = hashCode override fun toString() = - "EvalTextSimilarityGrader{evaluationMetric=$evaluationMetric, input=$input, passThreshold=$passThreshold, reference=$reference, type=$type, name=$name, additionalProperties=$additionalProperties}" + "TextSimilarityGrader{evaluationMetric=$evaluationMetric, input=$input, name=$name, reference=$reference, type=$type, additionalProperties=$additionalProperties}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelDeleteParams.kt index f87f9a5ae..c3b48aed3 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelDeleteParams.kt @@ -4,25 +4,25 @@ package com.openai.models.models import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Delete a fine-tuned model. You must have the Owner role in your organization to delete a model. */ class ModelDeleteParams private constructor( - private val model: String, + private val model: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun model(): String = model + fun model(): Optional = Optional.ofNullable(model) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -34,14 +34,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ModelDeleteParams]. - * - * The following fields are required: - * ```java - * .model() - * ``` - */ + @JvmStatic fun none(): ModelDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ModelDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -61,7 +56,10 @@ private constructor( additionalBodyProperties = modelDeleteParams.additionalBodyProperties.toMutableMap() } - fun model(model: String) = apply { this.model = model } + fun model(model: String?) = apply { this.model = model } + + /** Alias for calling [Builder.model] with `model.orElse(null)`. */ + fun model(model: Optional) = model(model.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -187,17 +185,10 @@ private constructor( * Returns an immutable instance of [ModelDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .model() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ModelDeleteParams = ModelDeleteParams( - checkRequired("model", model), + model, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -209,7 +200,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> model + 0 -> model ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPage.kt index 2da80544d..9ce4bde9f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPage.kt @@ -2,13 +2,12 @@ package com.openai.models.models +import com.openai.core.AutoPager import com.openai.core.JsonValue +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.ModelService import java.util.Objects -import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [ModelService.list] */ @@ -17,7 +16,7 @@ private constructor( private val service: ModelService, private val params: ModelListParams, private val response: ModelListPageResponse, -) { +) : Page { /** * Delegates to [ModelListPageResponse], but gracefully handles missing data. @@ -29,13 +28,16 @@ private constructor( /** @see [ModelListPageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + fun nextPageParams(): ModelListParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): ModelListPage = service.list(nextPageParams()) + + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): ModelListParams = params @@ -104,25 +106,6 @@ private constructor( ) } - class AutoPager(private val firstPage: ModelListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPageAsync.kt index 653a08f5a..335ac20c7 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelListPageAsync.kt @@ -2,23 +2,24 @@ package com.openai.models.models +import com.openai.core.AutoPagerAsync import com.openai.core.JsonValue +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.ModelServiceAsync import java.util.Objects -import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [ModelServiceAsync.list] */ class ModelListPageAsync private constructor( private val service: ModelServiceAsync, + private val streamHandlerExecutor: Executor, private val params: ModelListParams, private val response: ModelListPageResponse, -) { +) : PageAsync { /** * Delegates to [ModelListPageResponse], but gracefully handles missing data. @@ -30,16 +31,16 @@ private constructor( /** @see [ModelListPageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + fun nextPageParams(): ModelListParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) + + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): ModelListParams = params @@ -57,6 +58,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -68,18 +70,24 @@ private constructor( class Builder internal constructor() { private var service: ModelServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: ModelListParams? = null private var response: ModelListPageResponse? = null @JvmSynthetic internal fun from(modelListPageAsync: ModelListPageAsync) = apply { service = modelListPageAsync.service + streamHandlerExecutor = modelListPageAsync.streamHandlerExecutor params = modelListPageAsync.params response = modelListPageAsync.response } fun service(service: ModelServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: ModelListParams) = apply { this.params = params } @@ -94,6 +102,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -103,47 +112,22 @@ private constructor( fun build(): ModelListPageAsync = ModelListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: ModelListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (Model) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is ModelListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is ModelListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "ModelListPageAsync{service=$service, params=$params, response=$response}" + "ModelListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelRetrieveParams.kt index d76cdabc1..1be641852 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/models/ModelRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/models/ModelRetrieveParams.kt @@ -3,10 +3,11 @@ package com.openai.models.models import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Retrieves a model instance, providing basic information about the model such as the owner and @@ -14,12 +15,12 @@ import java.util.Objects */ class ModelRetrieveParams private constructor( - private val model: String, + private val model: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun model(): String = model + fun model(): Optional = Optional.ofNullable(model) fun _additionalHeaders(): Headers = additionalHeaders @@ -29,14 +30,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ModelRetrieveParams]. - * - * The following fields are required: - * ```java - * .model() - * ``` - */ + @JvmStatic fun none(): ModelRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ModelRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -54,7 +50,10 @@ private constructor( additionalQueryParams = modelRetrieveParams.additionalQueryParams.toBuilder() } - fun model(model: String) = apply { this.model = model } + fun model(model: String?) = apply { this.model = model } + + /** Alias for calling [Builder.model] with `model.orElse(null)`. */ + fun model(model: Optional) = model(model.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -158,25 +157,14 @@ private constructor( * Returns an immutable instance of [ModelRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .model() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ModelRetrieveParams = - ModelRetrieveParams( - checkRequired("model", model), - additionalHeaders.build(), - additionalQueryParams.build(), - ) + ModelRetrieveParams(model, additionalHeaders.build(), additionalQueryParams.build()) } fun _pathParam(index: Int): String = when (index) { - 0 -> model + 0 -> model ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt index 6b512ed99..345f6a939 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseCreateParams.kt @@ -19,6 +19,7 @@ import com.openai.core.Enum import com.openai.core.ExcludeMissing import com.openai.core.JsonField import com.openai.core.JsonMissing +import com.openai.core.JsonSchemaLocalValidation import com.openai.core.JsonValue import com.openai.core.Params import com.openai.core.allMaxBy @@ -784,6 +785,28 @@ private constructor( */ fun text(text: JsonField) = apply { body.text(text) } + /** + * Sets the text configuration's format to a JSON schema derived from the structure of the + * given class. This changes the builder to a type-safe + * [StructuredResponseCreateParams.Builder] that will build a + * [StructuredResponseCreateParams] instance when `build()` is called. + * + * @param responseType A class from which a JSON schema will be derived to define the text + * configuration's format. + * @param localValidation [JsonSchemaLocalValidation.YES] (the default) to validate the JSON + * schema locally when it is generated by this method to confirm that it adheres to the + * requirements and restrictions on JSON schemas imposed by the OpenAI specification; or + * [JsonSchemaLocalValidation.NO] to skip local validation and rely only on remote + * validation. See the SDK documentation for more details. + * @throws IllegalArgumentException If local validation is enabled, but it fails because a + * valid JSON schema cannot be derived from the given class. + */ + @JvmOverloads + fun text( + responseType: Class, + localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES, + ) = StructuredResponseCreateParams.builder().wrap(responseType, this, localValidation) + /** * How the model should select which tool (or tools) to use when generating a response. See * the `tools` parameter to see how to specify which tools the model can call. diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseDeleteParams.kt index b3fae35d2..38398d98a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseDeleteParams.kt @@ -4,23 +4,23 @@ package com.openai.models.responses import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Deletes a model response with the given ID. */ class ResponseDeleteParams private constructor( - private val responseId: String, + private val responseId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun responseId(): String = responseId + fun responseId(): Optional = Optional.ofNullable(responseId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ResponseDeleteParams]. - * - * The following fields are required: - * ```java - * .responseId() - * ``` - */ + @JvmStatic fun none(): ResponseDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ResponseDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,7 +54,10 @@ private constructor( additionalBodyProperties = responseDeleteParams.additionalBodyProperties.toMutableMap() } - fun responseId(responseId: String) = apply { this.responseId = responseId } + fun responseId(responseId: String?) = apply { this.responseId = responseId } + + /** Alias for calling [Builder.responseId] with `responseId.orElse(null)`. */ + fun responseId(responseId: Optional) = responseId(responseId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -185,17 +183,10 @@ private constructor( * Returns an immutable instance of [ResponseDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .responseId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ResponseDeleteParams = ResponseDeleteParams( - checkRequired("responseId", responseId), + responseId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -207,7 +198,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> responseId + 0 -> responseId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFileSearchToolCall.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFileSearchToolCall.kt index 35019c26a..1e0389b6e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFileSearchToolCall.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseFileSearchToolCall.kt @@ -497,7 +497,7 @@ private constructor( private val attributes: JsonField, private val fileId: JsonField, private val filename: JsonField, - private val score: JsonField, + private val score: JsonField, private val text: JsonField, private val additionalProperties: MutableMap, ) { @@ -511,7 +511,7 @@ private constructor( @JsonProperty("filename") @ExcludeMissing filename: JsonField = JsonMissing.of(), - @JsonProperty("score") @ExcludeMissing score: JsonField = JsonMissing.of(), + @JsonProperty("score") @ExcludeMissing score: JsonField = JsonMissing.of(), @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), ) : this(attributes, fileId, filename, score, text, mutableMapOf()) @@ -549,7 +549,7 @@ private constructor( * @throws OpenAIInvalidDataException if the JSON field has an unexpected type (e.g. if the * server responded with an unexpected value). */ - fun score(): Optional = score.getOptional("score") + fun score(): Optional = score.getOptional("score") /** * The text that was retrieved from the file. @@ -587,7 +587,7 @@ private constructor( * * Unlike [score], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("score") @ExcludeMissing fun _score(): JsonField = score + @JsonProperty("score") @ExcludeMissing fun _score(): JsonField = score /** * Returns the raw JSON value of [text]. @@ -620,7 +620,7 @@ private constructor( private var attributes: JsonField = JsonMissing.of() private var fileId: JsonField = JsonMissing.of() private var filename: JsonField = JsonMissing.of() - private var score: JsonField = JsonMissing.of() + private var score: JsonField = JsonMissing.of() private var text: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @@ -682,16 +682,16 @@ private constructor( fun filename(filename: JsonField) = apply { this.filename = filename } /** The relevance score of the file - a value between 0 and 1. */ - fun score(score: Double) = score(JsonField.of(score)) + fun score(score: Float) = score(JsonField.of(score)) /** * Sets [Builder.score] to an arbitrary JSON value. * - * You should usually call [Builder.score] with a well-typed [Double] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. + * You should usually call [Builder.score] with a well-typed [Float] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun score(score: JsonField) = apply { this.score = score } + fun score(score: JsonField) = apply { this.score = score } /** The text that was retrieved from the file. */ fun text(text: String) = text(JsonField.of(text)) diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseRetrieveParams.kt index 3c73de870..bc1589495 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/ResponseRetrieveParams.kt @@ -3,7 +3,6 @@ package com.openai.models.responses import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable @@ -14,13 +13,13 @@ import kotlin.jvm.optionals.getOrNull /** Retrieves a model response with the given ID. */ class ResponseRetrieveParams private constructor( - private val responseId: String, + private val responseId: String?, private val include: List?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun responseId(): String = responseId + fun responseId(): Optional = Optional.ofNullable(responseId) /** * Additional fields to include in the response. See the `include` parameter for Response @@ -36,14 +35,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [ResponseRetrieveParams]. - * - * The following fields are required: - * ```java - * .responseId() - * ``` - */ + @JvmStatic fun none(): ResponseRetrieveParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [ResponseRetrieveParams]. */ @JvmStatic fun builder() = Builder() } @@ -63,7 +57,10 @@ private constructor( additionalQueryParams = responseRetrieveParams.additionalQueryParams.toBuilder() } - fun responseId(responseId: String) = apply { this.responseId = responseId } + fun responseId(responseId: String?) = apply { this.responseId = responseId } + + /** Alias for calling [Builder.responseId] with `responseId.orElse(null)`. */ + fun responseId(responseId: Optional) = responseId(responseId.getOrNull()) /** * Additional fields to include in the response. See the `include` parameter for Response @@ -187,17 +184,10 @@ private constructor( * Returns an immutable instance of [ResponseRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .responseId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): ResponseRetrieveParams = ResponseRetrieveParams( - checkRequired("responseId", responseId), + responseId, include?.toImmutable(), additionalHeaders.build(), additionalQueryParams.build(), @@ -206,7 +196,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> responseId + 0 -> responseId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponse.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponse.kt new file mode 100644 index 000000000..f28865b0c --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponse.kt @@ -0,0 +1,197 @@ +package com.openai.models.responses + +import com.openai.core.JsonField +import com.openai.core.JsonValue +import com.openai.errors.OpenAIInvalidDataException +import com.openai.models.Reasoning +import com.openai.models.ResponsesModel +import java.util.Objects +import java.util.Optional + +/** + * A wrapper for [Response] that provides type-safe access to the [output] when using the + * _Structured Outputs_ feature to deserialize a JSON response to an instance of an arbitrary class. + * See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class to which the JSON data in the response will be deserialized. + */ +class StructuredResponse( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawResponse") val rawResponse: Response, +) { + /** @see Response.id */ + fun id(): String = rawResponse.id() + + /** @see Response.createdAt */ + fun createdAt(): Double = rawResponse.createdAt() + + /** @see Response.error */ + fun error(): Optional = rawResponse.error() + + /** @see Response.incompleteDetails */ + fun incompleteDetails(): Optional = rawResponse.incompleteDetails() + + /** @see Response.instructions */ + fun instructions(): Optional = rawResponse.instructions() + + /** @see Response.metadata */ + fun metadata(): Optional = rawResponse.metadata() + + /** @see Response.model */ + fun model(): ResponsesModel = rawResponse.model() + + /** @see Response._object_ */ + fun _object_(): JsonValue = rawResponse._object_() + + private val output by lazy { + rawResponse._output().map { outputs -> + outputs.map { StructuredResponseOutputItem(responseType, it) } + } + } + + /** @see Response.output */ + fun output(): List> = output.getRequired("output") + + /** @see Response.parallelToolCalls */ + fun parallelToolCalls(): Boolean = rawResponse.parallelToolCalls() + + /** @see Response.temperature */ + fun temperature(): Optional = rawResponse.temperature() + + /** @see Response.toolChoice */ + fun toolChoice(): Response.ToolChoice = rawResponse.toolChoice() + + /** @see Response.tools */ + fun tools(): List = rawResponse.tools() + + /** @see Response.topP */ + fun topP(): Optional = rawResponse.topP() + + /** @see Response.maxOutputTokens */ + fun maxOutputTokens(): Optional = rawResponse.maxOutputTokens() + + /** @see Response.previousResponseId */ + fun previousResponseId(): Optional = rawResponse.previousResponseId() + + /** @see Response.reasoning */ + fun reasoning(): Optional = rawResponse.reasoning() + + /** @see Response.serviceTier */ + fun serviceTier(): Optional = rawResponse.serviceTier() + + /** @see Response.status */ + fun status(): Optional = rawResponse.status() + + /** @see Response.text */ + fun text(): Optional = rawResponse.text() + + /** @see Response.truncation */ + fun truncation(): Optional = rawResponse.truncation() + + /** @see Response.usage */ + fun usage(): Optional = rawResponse.usage() + + /** @see Response.user */ + fun user(): Optional = rawResponse.user() + + /** @see Response._id */ + fun _id(): JsonField = rawResponse._id() + + /** @see Response._createdAt */ + fun _createdAt(): JsonField = rawResponse._createdAt() + + /** @see Response._error */ + fun _error(): JsonField = rawResponse._error() + + /** @see Response._incompleteDetails */ + fun _incompleteDetails(): JsonField = + rawResponse._incompleteDetails() + + /** @see Response._instructions */ + fun _instructions(): JsonField = rawResponse._instructions() + + /** @see Response._metadata */ + fun _metadata(): JsonField = rawResponse._metadata() + + /** @see Response._model */ + fun _model(): JsonField = rawResponse._model() + + /** @see Response._output */ + fun _output(): JsonField>> = output + + /** @see Response._parallelToolCalls */ + fun _parallelToolCalls(): JsonField = rawResponse._parallelToolCalls() + + /** @see Response._temperature */ + fun _temperature(): JsonField = rawResponse._temperature() + + /** @see Response._toolChoice */ + fun _toolChoice(): JsonField = rawResponse._toolChoice() + + /** @see Response._tools */ + fun _tools(): JsonField> = rawResponse._tools() + + /** @see Response._topP */ + fun _topP(): JsonField = rawResponse._topP() + + /** @see Response._maxOutputTokens */ + fun _maxOutputTokens(): JsonField = rawResponse._maxOutputTokens() + + /** @see Response._previousResponseId */ + fun _previousResponseId(): JsonField = rawResponse._previousResponseId() + + /** @see Response._reasoning */ + fun _reasoning(): JsonField = rawResponse._reasoning() + + /** @see Response._serviceTier */ + fun _serviceTier(): JsonField = rawResponse._serviceTier() + + /** @see Response._status */ + fun _status(): JsonField = rawResponse._status() + + /** @see Response._text */ + fun _text(): JsonField = rawResponse._text() + + /** @see Response._truncation */ + fun _truncation(): JsonField = rawResponse._truncation() + + /** @see Response._usage */ + fun _usage(): JsonField = rawResponse._usage() + + /** @see Response._user */ + fun _user(): JsonField = rawResponse._user() + + /** @see Response._additionalProperties */ + fun _additionalProperties(): Map = rawResponse._additionalProperties() + + /** @see Response.validate */ + fun validate(): StructuredResponse = apply { + output().forEach { it.validate() } + rawResponse.validate() + } + + /** @see Response.isValid */ + fun isValid(): Boolean = + try { + validate() + true + } catch (e: OpenAIInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + return other is StructuredResponse<*> && + responseType == other.responseType && + rawResponse == other.rawResponse + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawResponse) } + + override fun hashCode(): Int = hashCode + + override fun toString(): String = + "${javaClass.simpleName}{responseType=$responseType, rawResponse=$rawResponse}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseCreateParams.kt new file mode 100644 index 000000000..aae191ac7 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseCreateParams.kt @@ -0,0 +1,526 @@ +package com.openai.models.responses + +import com.openai.core.JsonField +import com.openai.core.JsonSchemaLocalValidation +import com.openai.core.JsonValue +import com.openai.core.checkRequired +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.textConfigFromClass +import com.openai.models.ChatModel +import com.openai.models.Reasoning +import com.openai.models.ResponsesModel +import java.util.Objects +import java.util.Optional + +/** + * A wrapper for [ResponseCreateParams] that provides a type-safe [Builder] that can record the + * [responseType] used to derive a JSON schema from an arbitrary class when using the _Structured + * Outputs_ feature. When a JSON response is received, it is deserialized to am instance of that + * type. See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class that will be used to derive the JSON schema in the request and to + * which the JSON response will be deserialized. + */ +class StructuredResponseCreateParams( + @get:JvmName("responseType") val responseType: Class, + /** + * The raw, underlying response create parameters wrapped by this structured instance of the + * parameters. + */ + @get:JvmName("rawParams") val rawParams: ResponseCreateParams, +) { + + companion object { + /** @see ResponseCreateParams.builder */ + @JvmStatic fun builder() = Builder() + } + + class Builder internal constructor() { + private var responseType: Class? = null + private var paramsBuilder = ResponseCreateParams.builder() + + @JvmSynthetic + internal fun wrap( + responseType: Class, + paramsBuilder: ResponseCreateParams.Builder, + localValidation: JsonSchemaLocalValidation, + ) = apply { + this.responseType = responseType + this.paramsBuilder = paramsBuilder + text(responseType, localValidation) + } + + /** Injects a given `ResponseCreateParams.Builder`. For use only when testing. */ + @JvmSynthetic + internal fun inject(paramsBuilder: ResponseCreateParams.Builder) = apply { + this.paramsBuilder = paramsBuilder + } + + // The `body(...)` function is deliberately not supported. + + /** @see ResponseCreateParams.Builder.input */ + fun input(input: ResponseCreateParams.Input) = apply { paramsBuilder.input(input) } + + /** @see ResponseCreateParams.Builder.input */ + fun input(input: JsonField) = apply { + paramsBuilder.input(input) + } + + /** @see ResponseCreateParams.Builder.input */ + fun input(text: String) = apply { paramsBuilder.input(text) } + + /** @see ResponseCreateParams.Builder.inputOfResponse */ + fun inputOfResponse(response: List) = apply { + paramsBuilder.inputOfResponse(response) + } + + /** @see ResponseCreateParams.Builder.model */ + fun model(model: ResponsesModel) = apply { paramsBuilder.model(model) } + + /** @see ResponseCreateParams.Builder.model */ + fun model(model: JsonField) = apply { paramsBuilder.model(model) } + + /** @see ResponseCreateParams.Builder.model */ + fun model(string: String) = apply { paramsBuilder.model(string) } + + /** @see ResponseCreateParams.Builder.model */ + fun model(chat: ChatModel) = apply { paramsBuilder.model(chat) } + + /** @see ResponseCreateParams.Builder.model */ + fun model(only: ResponsesModel.ResponsesOnlyModel) = apply { paramsBuilder.model(only) } + + /** @see ResponseCreateParams.Builder.include */ + fun include(include: List?) = apply { paramsBuilder.include(include) } + + /** @see ResponseCreateParams.Builder.include */ + fun include(include: Optional>) = apply { + paramsBuilder.include(include) + } + + /** @see ResponseCreateParams.Builder.include */ + fun include(include: JsonField>) = apply { + paramsBuilder.include(include) + } + + /** @see ResponseCreateParams.Builder.addInclude */ + fun addInclude(include: ResponseIncludable) = apply { paramsBuilder.addInclude(include) } + + /** @see ResponseCreateParams.Builder.instructions */ + fun instructions(instructions: String?) = apply { paramsBuilder.instructions(instructions) } + + /** @see ResponseCreateParams.Builder.instructions */ + fun instructions(instructions: Optional) = apply { + paramsBuilder.instructions(instructions) + } + + /** @see ResponseCreateParams.Builder.instructions */ + fun instructions(instructions: JsonField) = apply { + paramsBuilder.instructions(instructions) + } + + /** @see ResponseCreateParams.Builder.maxOutputTokens */ + fun maxOutputTokens(maxOutputTokens: Long?) = apply { + paramsBuilder.maxOutputTokens(maxOutputTokens) + } + + /** @see ResponseCreateParams.Builder.maxOutputTokens */ + fun maxOutputTokens(maxOutputTokens: Long) = apply { + paramsBuilder.maxOutputTokens(maxOutputTokens) + } + + /** @see ResponseCreateParams.Builder.maxOutputTokens */ + fun maxOutputTokens(maxOutputTokens: Optional) = apply { + paramsBuilder.maxOutputTokens(maxOutputTokens) + } + + /** @see ResponseCreateParams.Builder.maxOutputTokens */ + fun maxOutputTokens(maxOutputTokens: JsonField) = apply { + paramsBuilder.maxOutputTokens(maxOutputTokens) + } + + /** @see ResponseCreateParams.Builder.metadata */ + fun metadata(metadata: ResponseCreateParams.Metadata?) = apply { + paramsBuilder.metadata(metadata) + } + + /** @see ResponseCreateParams.Builder.metadata */ + fun metadata(metadata: Optional) = apply { + paramsBuilder.metadata(metadata) + } + + /** @see ResponseCreateParams.Builder.metadata */ + fun metadata(metadata: JsonField) = apply { + paramsBuilder.metadata(metadata) + } + + /** @see ResponseCreateParams.Builder.parallelToolCalls */ + fun parallelToolCalls(parallelToolCalls: Boolean?) = apply { + paramsBuilder.parallelToolCalls(parallelToolCalls) + } + + /** @see ResponseCreateParams.Builder.parallelToolCalls */ + fun parallelToolCalls(parallelToolCalls: Boolean) = apply { + paramsBuilder.parallelToolCalls(parallelToolCalls) + } + + /** @see ResponseCreateParams.Builder.parallelToolCalls */ + fun parallelToolCalls(parallelToolCalls: Optional) = apply { + paramsBuilder.parallelToolCalls(parallelToolCalls) + } + + /** @see ResponseCreateParams.Builder.parallelToolCalls */ + fun parallelToolCalls(parallelToolCalls: JsonField) = apply { + paramsBuilder.parallelToolCalls(parallelToolCalls) + } + + /** @see ResponseCreateParams.Builder.previousResponseId */ + fun previousResponseId(previousResponseId: String?) = apply { + paramsBuilder.previousResponseId(previousResponseId) + } + + /** @see ResponseCreateParams.Builder.previousResponseId */ + fun previousResponseId(previousResponseId: Optional) = apply { + paramsBuilder.previousResponseId(previousResponseId) + } + + /** @see ResponseCreateParams.Builder.previousResponseId */ + fun previousResponseId(previousResponseId: JsonField) = apply { + paramsBuilder.previousResponseId(previousResponseId) + } + + /** @see ResponseCreateParams.Builder.reasoning */ + fun reasoning(reasoning: Reasoning?) = apply { paramsBuilder.reasoning(reasoning) } + + /** @see ResponseCreateParams.Builder.reasoning */ + fun reasoning(reasoning: Optional) = apply { paramsBuilder.reasoning(reasoning) } + + /** @see ResponseCreateParams.Builder.reasoning */ + fun reasoning(reasoning: JsonField) = apply { + paramsBuilder.reasoning(reasoning) + } + + /** @see ResponseCreateParams.Builder.serviceTier */ + fun serviceTier(serviceTier: ResponseCreateParams.ServiceTier?) = apply { + paramsBuilder.serviceTier(serviceTier) + } + + /** @see ResponseCreateParams.Builder.serviceTier */ + fun serviceTier(serviceTier: Optional) = apply { + paramsBuilder.serviceTier(serviceTier) + } + + /** @see ResponseCreateParams.Builder.serviceTier */ + fun serviceTier(serviceTier: JsonField) = apply { + paramsBuilder.serviceTier(serviceTier) + } + + /** @see ResponseCreateParams.Builder.store */ + fun store(store: Boolean?) = apply { paramsBuilder.store(store) } + + /** @see ResponseCreateParams.Builder.store */ + fun store(store: Boolean) = apply { paramsBuilder.store(store) } + + /** @see ResponseCreateParams.Builder.store */ + fun store(store: Optional) = apply { paramsBuilder.store(store) } + + /** @see ResponseCreateParams.Builder.store */ + fun store(store: JsonField) = apply { paramsBuilder.store(store) } + + /** @see ResponseCreateParams.Builder.temperature */ + fun temperature(temperature: Double?) = apply { paramsBuilder.temperature(temperature) } + + /** @see ResponseCreateParams.Builder.temperature */ + fun temperature(temperature: Double) = apply { paramsBuilder.temperature(temperature) } + + /** @see ResponseCreateParams.Builder.temperature */ + fun temperature(temperature: Optional) = apply { + paramsBuilder.temperature(temperature) + } + + /** @see ResponseCreateParams.Builder.temperature */ + fun temperature(temperature: JsonField) = apply { + paramsBuilder.temperature(temperature) + } + + /** + * Sets the text configuration's format to a JSON schema derived from the structure of the + * given class. + * + * @see ResponseCreateParams.Builder.text + */ + @JvmOverloads + fun text( + responseType: Class, + localValidation: JsonSchemaLocalValidation = JsonSchemaLocalValidation.YES, + ) = apply { + this.responseType = responseType + paramsBuilder.text(textConfigFromClass(responseType, localValidation)) + } + + /** @see ResponseCreateParams.Builder.toolChoice */ + fun toolChoice(toolChoice: ResponseCreateParams.ToolChoice) = apply { + paramsBuilder.toolChoice(toolChoice) + } + + /** @see ResponseCreateParams.Builder.toolChoice */ + fun toolChoice(toolChoice: JsonField) = apply { + paramsBuilder.toolChoice(toolChoice) + } + + /** @see ResponseCreateParams.Builder.toolChoice */ + fun toolChoice(options: ToolChoiceOptions) = apply { paramsBuilder.toolChoice(options) } + + /** @see ResponseCreateParams.Builder.toolChoice */ + fun toolChoice(types: ToolChoiceTypes) = apply { paramsBuilder.toolChoice(types) } + + /** @see ResponseCreateParams.Builder.toolChoice */ + fun toolChoice(function: ToolChoiceFunction) = apply { paramsBuilder.toolChoice(function) } + + /** @see ResponseCreateParams.Builder.tools */ + fun tools(tools: List) = apply { paramsBuilder.tools(tools) } + + /** @see ResponseCreateParams.Builder.tools */ + fun tools(tools: JsonField>) = apply { paramsBuilder.tools(tools) } + + /** @see ResponseCreateParams.Builder.addTool */ + fun addTool(tool: Tool) = apply { paramsBuilder.addTool(tool) } + + /** @see ResponseCreateParams.Builder.addTool */ + fun addTool(fileSearch: FileSearchTool) = apply { paramsBuilder.addTool(fileSearch) } + + /** @see ResponseCreateParams.Builder.addFileSearchTool */ + fun addFileSearchTool(vectorStoreIds: List) = apply { + paramsBuilder.addFileSearchTool(vectorStoreIds) + } + + /** @see ResponseCreateParams.Builder.addTool */ + fun addTool(function: FunctionTool) = apply { paramsBuilder.addTool(function) } + + /** @see ResponseCreateParams.Builder.addTool */ + fun addTool(webSearch: WebSearchTool) = apply { paramsBuilder.addTool(webSearch) } + + /** @see ResponseCreateParams.Builder.addTool */ + fun addTool(computerUsePreview: ComputerTool) = apply { + paramsBuilder.addTool(computerUsePreview) + } + + /** @see ResponseCreateParams.Builder.topP */ + fun topP(topP: Double?) = apply { paramsBuilder.topP(topP) } + + /** @see ResponseCreateParams.Builder.topP */ + fun topP(topP: Double) = apply { paramsBuilder.topP(topP) } + + /** @see ResponseCreateParams.Builder.topP */ + fun topP(topP: Optional) = apply { paramsBuilder.topP(topP) } + + /** @see ResponseCreateParams.Builder.topP */ + fun topP(topP: JsonField) = apply { paramsBuilder.topP(topP) } + + /** @see ResponseCreateParams.Builder.truncation */ + fun truncation(truncation: ResponseCreateParams.Truncation?) = apply { + paramsBuilder.truncation(truncation) + } + + /** @see ResponseCreateParams.Builder.truncation */ + fun truncation(truncation: Optional) = apply { + paramsBuilder.truncation(truncation) + } + + /** @see ResponseCreateParams.Builder.truncation */ + fun truncation(truncation: JsonField) = apply { + paramsBuilder.truncation(truncation) + } + + /** @see ResponseCreateParams.Builder.user */ + fun user(user: String) = apply { paramsBuilder.user(user) } + + /** @see ResponseCreateParams.Builder.user */ + fun user(user: JsonField) = apply { paramsBuilder.user(user) } + + /** @see ResponseCreateParams.Builder.additionalBodyProperties */ + fun additionalBodyProperties(additionalBodyProperties: Map) = apply { + paramsBuilder.additionalBodyProperties(additionalBodyProperties) + } + + /** @see ResponseCreateParams.Builder.putAdditionalBodyProperty */ + fun putAdditionalBodyProperty(key: String, value: JsonValue) = apply { + paramsBuilder.putAdditionalBodyProperty(key, value) + } + + /** @see ResponseCreateParams.Builder.putAllAdditionalBodyProperties */ + fun putAllAdditionalBodyProperties(additionalBodyProperties: Map) = + apply { + paramsBuilder.putAllAdditionalBodyProperties(additionalBodyProperties) + } + + /** @see ResponseCreateParams.Builder.removeAdditionalBodyProperty */ + fun removeAdditionalBodyProperty(key: String) = apply { + paramsBuilder.removeAdditionalBodyProperty(key) + } + + /** @see ResponseCreateParams.Builder.removeAllAdditionalBodyProperties */ + fun removeAllAdditionalBodyProperties(keys: Set) = apply { + paramsBuilder.removeAllAdditionalBodyProperties(keys) + } + + /** @see ResponseCreateParams.Builder.additionalHeaders */ + fun additionalHeaders(additionalHeaders: Headers) = apply { + paramsBuilder.additionalHeaders(additionalHeaders) + } + + /** @see ResponseCreateParams.Builder.additionalHeaders */ + fun additionalHeaders(additionalHeaders: Map>) = apply { + paramsBuilder.additionalHeaders(additionalHeaders) + } + + /** @see ResponseCreateParams.Builder.putAdditionalHeader */ + fun putAdditionalHeader(name: String, value: String) = apply { + paramsBuilder.putAdditionalHeader(name, value) + } + + /** @see ResponseCreateParams.Builder.putAdditionalHeaders */ + fun putAdditionalHeaders(name: String, values: Iterable) = apply { + paramsBuilder.putAdditionalHeaders(name, values) + } + + /** @see ResponseCreateParams.Builder.putAllAdditionalHeaders */ + fun putAllAdditionalHeaders(additionalHeaders: Headers) = apply { + paramsBuilder.putAllAdditionalHeaders(additionalHeaders) + } + + /** @see ResponseCreateParams.Builder.putAllAdditionalHeaders */ + fun putAllAdditionalHeaders(additionalHeaders: Map>) = apply { + paramsBuilder.putAllAdditionalHeaders(additionalHeaders) + } + + /** @see ResponseCreateParams.Builder.replaceAdditionalHeaders */ + fun replaceAdditionalHeaders(name: String, value: String) = apply { + paramsBuilder.replaceAdditionalHeaders(name, value) + } + + /** @see ResponseCreateParams.Builder.replaceAdditionalHeaders */ + fun replaceAdditionalHeaders(name: String, values: Iterable) = apply { + paramsBuilder.replaceAdditionalHeaders(name, values) + } + + /** @see ResponseCreateParams.Builder.replaceAllAdditionalHeaders */ + fun replaceAllAdditionalHeaders(additionalHeaders: Headers) = apply { + paramsBuilder.replaceAllAdditionalHeaders(additionalHeaders) + } + + /** @see ResponseCreateParams.Builder.replaceAllAdditionalHeaders */ + fun replaceAllAdditionalHeaders(additionalHeaders: Map>) = apply { + paramsBuilder.replaceAllAdditionalHeaders(additionalHeaders) + } + + /** @see ResponseCreateParams.Builder.removeAdditionalHeaders */ + fun removeAdditionalHeaders(name: String) = apply { + paramsBuilder.removeAdditionalHeaders(name) + } + + /** @see ResponseCreateParams.Builder.removeAllAdditionalHeaders */ + fun removeAllAdditionalHeaders(names: Set) = apply { + paramsBuilder.removeAllAdditionalHeaders(names) + } + + /** @see ResponseCreateParams.Builder.additionalQueryParams */ + fun additionalQueryParams(additionalQueryParams: QueryParams) = apply { + paramsBuilder.additionalQueryParams(additionalQueryParams) + } + + /** @see ResponseCreateParams.Builder.additionalQueryParams */ + fun additionalQueryParams(additionalQueryParams: Map>) = apply { + paramsBuilder.additionalQueryParams(additionalQueryParams) + } + + /** @see ResponseCreateParams.Builder.putAdditionalQueryParam */ + fun putAdditionalQueryParam(key: String, value: String) = apply { + paramsBuilder.putAdditionalQueryParam(key, value) + } + + /** @see ResponseCreateParams.Builder.putAdditionalQueryParams */ + fun putAdditionalQueryParams(key: String, values: Iterable) = apply { + paramsBuilder.putAdditionalQueryParams(key, values) + } + + /** @see ResponseCreateParams.Builder.putAllAdditionalQueryParams */ + fun putAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + paramsBuilder.putAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ResponseCreateParams.Builder.putAllAdditionalQueryParams */ + fun putAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + paramsBuilder.putAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ResponseCreateParams.Builder.replaceAdditionalQueryParams */ + fun replaceAdditionalQueryParams(key: String, value: String) = apply { + paramsBuilder.replaceAdditionalQueryParams(key, value) + } + + /** @see ResponseCreateParams.Builder.replaceAdditionalQueryParams */ + fun replaceAdditionalQueryParams(key: String, values: Iterable) = apply { + paramsBuilder.replaceAdditionalQueryParams(key, values) + } + + /** @see ResponseCreateParams.Builder.replaceAllAdditionalQueryParams */ + fun replaceAllAdditionalQueryParams(additionalQueryParams: QueryParams) = apply { + paramsBuilder.replaceAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ResponseCreateParams.Builder.replaceAllAdditionalQueryParams */ + fun replaceAllAdditionalQueryParams(additionalQueryParams: Map>) = + apply { + paramsBuilder.replaceAllAdditionalQueryParams(additionalQueryParams) + } + + /** @see ResponseCreateParams.Builder.removeAdditionalQueryParams */ + fun removeAdditionalQueryParams(key: String) = apply { + paramsBuilder.removeAdditionalQueryParams(key) + } + + /** @see ResponseCreateParams.Builder.removeAllAdditionalQueryParams */ + fun removeAllAdditionalQueryParams(keys: Set) = apply { + paramsBuilder.removeAllAdditionalQueryParams(keys) + } + + /** + * Returns an immutable instance of [ResponseCreateParams]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .input() + * .model() + * .text() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build() = + StructuredResponseCreateParams( + checkRequired("responseType", responseType), + paramsBuilder.build(), + ) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StructuredResponseCreateParams<*> && + responseType == other.responseType && + rawParams == other.rawParams + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawParams) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "${javaClass.simpleName}{responseType=$responseType, rawParams=$rawParams}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseOutputItem.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseOutputItem.kt new file mode 100644 index 000000000..39cd6b6b4 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseOutputItem.kt @@ -0,0 +1,189 @@ +package com.openai.models.responses + +import com.openai.core.JsonValue +import com.openai.errors.OpenAIInvalidDataException +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrElse +import kotlin.jvm.optionals.getOrNull + +/** + * A wrapper for [ResponseOutputItem] that provides type-safe access to the [message] when using the + * _Structured Outputs_ feature to deserialize a JSON response to an instance of an arbitrary class. + * See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class to which the JSON data in the content will be deserialized when + * [message] is called. + */ +class StructuredResponseOutputItem( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawOutputItem") val rawOutputItem: ResponseOutputItem, +) { + private val message by lazy { + rawOutputItem.message().map { StructuredResponseOutputMessage(responseType, it) } + } + + /** @see ResponseOutputItem.message */ + fun message(): Optional> = message + + /** @see ResponseOutputItem.fileSearchCall */ + fun fileSearchCall(): Optional = rawOutputItem.fileSearchCall() + + /** @see ResponseOutputItem.functionCall */ + fun functionCall(): Optional = rawOutputItem.functionCall() + + /** @see ResponseOutputItem.webSearchCall */ + fun webSearchCall(): Optional = rawOutputItem.webSearchCall() + + /** @see ResponseOutputItem.computerCall */ + fun computerCall(): Optional = rawOutputItem.computerCall() + + /** @see ResponseOutputItem.reasoning */ + fun reasoning(): Optional = rawOutputItem.reasoning() + + /** @see ResponseOutputItem.isMessage */ + fun isMessage(): Boolean = message().isPresent + + /** @see ResponseOutputItem.isFileSearchCall */ + fun isFileSearchCall(): Boolean = rawOutputItem.isFileSearchCall() + + /** @see ResponseOutputItem.isFunctionCall */ + fun isFunctionCall(): Boolean = rawOutputItem.isFunctionCall() + + /** @see ResponseOutputItem.isWebSearchCall */ + fun isWebSearchCall(): Boolean = rawOutputItem.isWebSearchCall() + + /** @see ResponseOutputItem.isComputerCall */ + fun isComputerCall(): Boolean = rawOutputItem.isComputerCall() + + /** @see ResponseOutputItem.isReasoning */ + fun isReasoning(): Boolean = rawOutputItem.isReasoning() + + /** @see ResponseOutputItem.asMessage */ + fun asMessage(): StructuredResponseOutputMessage = + message.getOrElse { + // Same behavior as `com.openai.core.getOrThrow` used by the delegate class. + throw OpenAIInvalidDataException("`message` is not present") + } + + /** @see ResponseOutputItem.asFileSearchCall */ + fun asFileSearchCall(): ResponseFileSearchToolCall = rawOutputItem.asFileSearchCall() + + /** @see ResponseOutputItem.asFunctionCall */ + fun asFunctionCall(): ResponseFunctionToolCall = rawOutputItem.asFunctionCall() + + /** @see ResponseOutputItem.asWebSearchCall */ + fun asWebSearchCall(): ResponseFunctionWebSearch = rawOutputItem.asWebSearchCall() + + /** @see ResponseOutputItem.asComputerCall */ + fun asComputerCall(): ResponseComputerToolCall = rawOutputItem.asComputerCall() + + /** @see ResponseOutputItem.asReasoning */ + fun asReasoning(): ResponseReasoningItem = rawOutputItem.asReasoning() + + /** @see ResponseOutputItem._json */ + fun _json(): Optional = rawOutputItem._json() + + /** @see ResponseOutputItem.accept */ + fun accept(visitor: Visitor): R = + when { + isMessage() -> visitor.visitMessage(asMessage()) + isFileSearchCall() -> visitor.visitFileSearchCall(asFileSearchCall()) + isFunctionCall() -> visitor.visitFunctionCall(asFunctionCall()) + isWebSearchCall() -> visitor.visitWebSearchCall(asWebSearchCall()) + isComputerCall() -> visitor.visitComputerCall(asComputerCall()) + isReasoning() -> visitor.visitReasoning(asReasoning()) + else -> visitor.unknown(_json().getOrNull()) + } + + private var validated: Boolean = false + + /** @see ResponseOutputItem.validate */ + fun validate(): StructuredResponseOutputItem = apply { + if (validated) { + return@apply + } + + accept( + object : Visitor { + override fun visitMessage(message: StructuredResponseOutputMessage) { + message.validate() + } + + override fun visitFileSearchCall(fileSearchCall: ResponseFileSearchToolCall) { + fileSearchCall.validate() + } + + override fun visitFunctionCall(functionCall: ResponseFunctionToolCall) { + functionCall.validate() + } + + override fun visitWebSearchCall(webSearchCall: ResponseFunctionWebSearch) { + webSearchCall.validate() + } + + override fun visitComputerCall(computerCall: ResponseComputerToolCall) { + computerCall.validate() + } + + override fun visitReasoning(reasoning: ResponseReasoningItem) { + reasoning.validate() + } + } + ) + validated = true + } + + /** @see ResponseOutputItem.isValid */ + fun isValid(): Boolean = + try { + validate() + true + } catch (_: OpenAIInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StructuredResponseOutputItem<*> && + responseType == other.responseType && + rawOutputItem == other.rawOutputItem + } + + override fun hashCode(): Int = Objects.hash(responseType, rawOutputItem) + + override fun toString(): String = + "${javaClass.simpleName}{responseType=$responseType, rawOutputItem=$rawOutputItem}" + + /** @see ResponseOutputItem.Visitor */ + // In keeping with the delegate's `Visitor`, `T` is used to refer to the return type of each + // function. `R` (for "Response") is used to refer to the response type, which is otherwise + // named `T` in the outer class, but confusion here is probably preferable to confusion there. + interface Visitor { + /** @see ResponseOutputItem.Visitor.visitMessage */ + fun visitMessage(message: StructuredResponseOutputMessage): T + + /** @see ResponseOutputItem.Visitor.visitFileSearchCall */ + fun visitFileSearchCall(fileSearchCall: ResponseFileSearchToolCall): T + + /** @see ResponseOutputItem.Visitor.visitFunctionCall */ + fun visitFunctionCall(functionCall: ResponseFunctionToolCall): T + + /** @see ResponseOutputItem.Visitor.visitWebSearchCall */ + fun visitWebSearchCall(webSearchCall: ResponseFunctionWebSearch): T + + /** @see ResponseOutputItem.Visitor.visitComputerCall */ + fun visitComputerCall(computerCall: ResponseComputerToolCall): T + + /** @see ResponseOutputItem.Visitor.visitReasoning */ + fun visitReasoning(reasoning: ResponseReasoningItem): T + + /** @see ResponseOutputItem.Visitor.unknown */ + fun unknown(json: JsonValue?): T { + throw OpenAIInvalidDataException("Unknown ResponseOutputItem: $json") + } + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseOutputMessage.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseOutputMessage.kt new file mode 100644 index 000000000..b7083a251 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/StructuredResponseOutputMessage.kt @@ -0,0 +1,181 @@ +package com.openai.models.responses + +import com.openai.core.JsonField +import com.openai.core.JsonValue +import com.openai.core.responseTypeFromJson +import com.openai.errors.OpenAIInvalidDataException +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrElse +import kotlin.jvm.optionals.getOrNull + +/** + * A wrapper for [ResponseOutputMessage] that provides type-safe access to the [content] when using + * the _Structured Outputs_ feature to deserialize a JSON response to an instance of an arbitrary + * class. See the SDK documentation for more details on _Structured Outputs_. + * + * @param T The type of the class to which the JSON data in the content will be deserialized when + * the output text of the [content] is retrieved. + */ +class StructuredResponseOutputMessage( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawMessage") val rawMessage: ResponseOutputMessage, +) { + /** @see ResponseOutputMessage.id */ + fun id(): String = rawMessage.id() + + private val content by lazy { + rawMessage._content().map { contents -> contents.map { Content(responseType, it) } } + } + + /** @see ResponseOutputMessage.content */ + fun content(): List> = content.getRequired("content") + + /** @see ResponseOutputMessage._role */ + fun _role(): JsonValue = rawMessage._role() + + /** @see ResponseOutputMessage.status */ + fun status(): ResponseOutputMessage.Status = rawMessage.status() + + /** @see ResponseOutputMessage._type */ + fun _type(): JsonValue = rawMessage._type() + + /** @see ResponseOutputMessage._id */ + fun _id(): JsonField = rawMessage._id() + + /** @see ResponseOutputMessage._content */ + fun _content(): JsonField>> = content + + /** @see ResponseOutputMessage._status */ + fun _status(): JsonField = rawMessage._status() + + /** @see ResponseOutputMessage._additionalProperties */ + fun _additionalProperties(): Map = rawMessage._additionalProperties() + + /** @see ResponseOutputMessage.validate */ + fun validate(): StructuredResponseOutputMessage = apply { + // `content()` is a different type to that in the delegate class. + content().forEach { it.validate() } + rawMessage.validate() + } + + /** @see ResponseOutputMessage.isValid */ + fun isValid(): Boolean = + try { + validate() + true + } catch (_: OpenAIInvalidDataException) { + false + } + + /** @see ResponseOutputMessage.Content */ + class Content( + @get:JvmName("responseType") val responseType: Class, + @get:JvmName("rawContent") val rawContent: ResponseOutputMessage.Content, + ) { + private val outputText by lazy { + rawContent.outputText().map { responseTypeFromJson(it.text(), responseType) } + } + + /** + * Gets the output text, but deserialized to an instance of the response type class. + * + * @see ResponseOutputMessage.Content.outputText + */ + fun outputText(): Optional = outputText + + /** @see ResponseOutputMessage.Content.refusal */ + fun refusal(): Optional = rawContent.refusal() + + /** @see ResponseOutputMessage.Content.isOutputText */ + // No need to check `outputText`; the delegate can just check the source value is present. + fun isOutputText(): Boolean = rawContent.isOutputText() + + /** @see ResponseOutputMessage.Content.isRefusal */ + fun isRefusal(): Boolean = rawContent.isRefusal() + + /** @see ResponseOutputMessage.Content.asOutputText */ + fun asOutputText(): T = + outputText.getOrElse { + // Same behavior as `com.openai.core.getOrThrow` used by the delegate class. + throw OpenAIInvalidDataException("`outputText` is not present") + } + + /** @see ResponseOutputMessage.Content.asRefusal */ + fun asRefusal(): ResponseOutputRefusal = rawContent.asRefusal() + + /** @see ResponseOutputMessage.Content._json */ + fun _json(): Optional = rawContent._json() + + /** @see ResponseOutputMessage.Content.accept */ + fun accept(visitor: Visitor): R = + when { + outputText.isPresent -> visitor.visitOutputText(outputText.get()) + refusal().isPresent -> visitor.visitRefusal(refusal().get()) + else -> visitor.unknown(_json().getOrNull()) + } + + /** @see ResponseOutputMessage.Content.validate */ + fun validate(): Content = apply { + // The `outputText` object, as it is a user-defined type that is unlikely to have a + // `validate()` function/method, so validate the underlying `ResponseOutputText` from + // which it is derived. That can be done by the delegate class. + rawContent.validate() + } + + /** @see ResponseOutputMessage.Content.isValid */ + fun isValid(): Boolean = + try { + validate() + true + } catch (_: OpenAIInvalidDataException) { + false + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Content<*> && + rawContent == other.rawContent && + responseType == other.responseType + } + + override fun hashCode(): Int = Objects.hash(rawContent, responseType) + + override fun toString(): String = + "${javaClass.simpleName}{responseType=$responseType, rawContent=$rawContent}" + + /** @see ResponseOutputMessage.Content.Visitor */ + interface Visitor { + /** @see ResponseOutputMessage.Content.Visitor.visitOutputText */ + fun visitOutputText(outputText: T): R + + /** @see ResponseOutputMessage.Content.Visitor.visitRefusal */ + fun visitRefusal(refusal: ResponseOutputRefusal): R + + /** @see ResponseOutputMessage.Content.Visitor.unknown */ + fun unknown(json: JsonValue?): R { + throw OpenAIInvalidDataException("Unknown Content: $json") + } + } + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StructuredResponseOutputMessage<*> && + responseType == other.responseType && + rawMessage == other.rawMessage + } + + private val hashCode: Int by lazy { Objects.hash(responseType, rawMessage) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "${javaClass.simpleName}{responseType=$responseType, rawMessage=$rawMessage}" +} diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPage.kt index 1fbb02eff..6218c55b3 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPage.kt @@ -2,6 +2,8 @@ package com.openai.models.responses.inputitems +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.models.responses.ResponseComputerToolCall import com.openai.models.responses.ResponseComputerToolCallOutputItem @@ -15,8 +17,6 @@ import com.openai.models.responses.ResponseOutputMessage import com.openai.services.blocking.responses.InputItemService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [InputItemService.list] */ @@ -25,7 +25,7 @@ private constructor( private val service: InputItemService, private val params: InputItemListParams, private val response: ResponseItemList, -) { +) : Page { /** * Delegates to [ResponseItemList], but gracefully handles missing data. @@ -41,63 +41,57 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() - - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } - - return Optional.of( - params - .toBuilder() - .after( - data() - .last() - .accept( - object : ResponseItem.Visitor> { - override fun visitResponseInputMessageItem( - responseInputMessageItem: ResponseInputMessageItem - ): Optional = - responseInputMessageItem._id().getOptional("id") - - override fun visitResponseOutputMessage( - responseOutputMessage: ResponseOutputMessage - ): Optional = responseOutputMessage._id().getOptional("id") - - override fun visitFileSearchCall( - fileSearchCall: ResponseFileSearchToolCall - ): Optional = fileSearchCall._id().getOptional("id") - - override fun visitComputerCall( - computerCall: ResponseComputerToolCall - ): Optional = computerCall._id().getOptional("id") - - override fun visitComputerCallOutput( - computerCallOutput: ResponseComputerToolCallOutputItem - ): Optional = computerCallOutput._id().getOptional("id") - - override fun visitWebSearchCall( - webSearchCall: ResponseFunctionWebSearch - ): Optional = webSearchCall._id().getOptional("id") - - override fun visitFunctionCall( - functionCall: ResponseFunctionToolCallItem - ): Optional = functionCall._id().getOptional("id") - - override fun visitFunctionCallOutput( - functionCallOutput: ResponseFunctionToolCallOutputItem - ): Optional = functionCallOutput._id().getOptional("id") - } - ) - ) - .build() - ) - } + override fun items(): List = data() + + override fun hasNextPage(): Boolean = items().isNotEmpty() + + fun nextPageParams(): InputItemListParams = + params + .toBuilder() + .after( + items() + .last() + .accept( + object : ResponseItem.Visitor> { + override fun visitResponseInputMessageItem( + responseInputMessageItem: ResponseInputMessageItem + ): Optional = responseInputMessageItem._id().getOptional("id") + + override fun visitResponseOutputMessage( + responseOutputMessage: ResponseOutputMessage + ): Optional = responseOutputMessage._id().getOptional("id") + + override fun visitFileSearchCall( + fileSearchCall: ResponseFileSearchToolCall + ): Optional = fileSearchCall._id().getOptional("id") + + override fun visitComputerCall( + computerCall: ResponseComputerToolCall + ): Optional = computerCall._id().getOptional("id") + + override fun visitComputerCallOutput( + computerCallOutput: ResponseComputerToolCallOutputItem + ): Optional = computerCallOutput._id().getOptional("id") + + override fun visitWebSearchCall( + webSearchCall: ResponseFunctionWebSearch + ): Optional = webSearchCall._id().getOptional("id") + + override fun visitFunctionCall( + functionCall: ResponseFunctionToolCallItem + ): Optional = functionCall._id().getOptional("id") + + override fun visitFunctionCallOutput( + functionCallOutput: ResponseFunctionToolCallOutputItem + ): Optional = functionCallOutput._id().getOptional("id") + } + ) + ) + .build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): InputItemListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): InputItemListParams = params @@ -166,25 +160,6 @@ private constructor( ) } - class AutoPager(private val firstPage: InputItemListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPageAsync.kt index ddde7ff4d..a840b3108 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListPageAsync.kt @@ -2,6 +2,8 @@ package com.openai.models.responses.inputitems +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.models.responses.ResponseComputerToolCall import com.openai.models.responses.ResponseComputerToolCallOutputItem @@ -17,16 +19,16 @@ import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [InputItemServiceAsync.list] */ class InputItemListPageAsync private constructor( private val service: InputItemServiceAsync, + private val streamHandlerExecutor: Executor, private val params: InputItemListParams, private val response: ResponseItemList, -) { +) : PageAsync { /** * Delegates to [ResponseItemList], but gracefully handles missing data. @@ -42,66 +44,58 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() - - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } - - return Optional.of( - params - .toBuilder() - .after( - data() - .last() - .accept( - object : ResponseItem.Visitor> { - override fun visitResponseInputMessageItem( - responseInputMessageItem: ResponseInputMessageItem - ): Optional = - responseInputMessageItem._id().getOptional("id") - - override fun visitResponseOutputMessage( - responseOutputMessage: ResponseOutputMessage - ): Optional = responseOutputMessage._id().getOptional("id") - - override fun visitFileSearchCall( - fileSearchCall: ResponseFileSearchToolCall - ): Optional = fileSearchCall._id().getOptional("id") - - override fun visitComputerCall( - computerCall: ResponseComputerToolCall - ): Optional = computerCall._id().getOptional("id") - - override fun visitComputerCallOutput( - computerCallOutput: ResponseComputerToolCallOutputItem - ): Optional = computerCallOutput._id().getOptional("id") - - override fun visitWebSearchCall( - webSearchCall: ResponseFunctionWebSearch - ): Optional = webSearchCall._id().getOptional("id") - - override fun visitFunctionCall( - functionCall: ResponseFunctionToolCallItem - ): Optional = functionCall._id().getOptional("id") - - override fun visitFunctionCallOutput( - functionCallOutput: ResponseFunctionToolCallOutputItem - ): Optional = functionCallOutput._id().getOptional("id") - } - ) - ) - .build() - ) - } + override fun items(): List = data() + + override fun hasNextPage(): Boolean = items().isNotEmpty() + + fun nextPageParams(): InputItemListParams = + params + .toBuilder() + .after( + items() + .last() + .accept( + object : ResponseItem.Visitor> { + override fun visitResponseInputMessageItem( + responseInputMessageItem: ResponseInputMessageItem + ): Optional = responseInputMessageItem._id().getOptional("id") + + override fun visitResponseOutputMessage( + responseOutputMessage: ResponseOutputMessage + ): Optional = responseOutputMessage._id().getOptional("id") + + override fun visitFileSearchCall( + fileSearchCall: ResponseFileSearchToolCall + ): Optional = fileSearchCall._id().getOptional("id") + + override fun visitComputerCall( + computerCall: ResponseComputerToolCall + ): Optional = computerCall._id().getOptional("id") + + override fun visitComputerCallOutput( + computerCallOutput: ResponseComputerToolCallOutputItem + ): Optional = computerCallOutput._id().getOptional("id") + + override fun visitWebSearchCall( + webSearchCall: ResponseFunctionWebSearch + ): Optional = webSearchCall._id().getOptional("id") + + override fun visitFunctionCall( + functionCall: ResponseFunctionToolCallItem + ): Optional = functionCall._id().getOptional("id") + + override fun visitFunctionCallOutput( + functionCallOutput: ResponseFunctionToolCallOutputItem + ): Optional = functionCallOutput._id().getOptional("id") + } + ) + ) + .build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): InputItemListParams = params @@ -119,6 +113,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -130,18 +125,24 @@ private constructor( class Builder internal constructor() { private var service: InputItemServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: InputItemListParams? = null private var response: ResponseItemList? = null @JvmSynthetic internal fun from(inputItemListPageAsync: InputItemListPageAsync) = apply { service = inputItemListPageAsync.service + streamHandlerExecutor = inputItemListPageAsync.streamHandlerExecutor params = inputItemListPageAsync.params response = inputItemListPageAsync.response } fun service(service: InputItemServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: InputItemListParams) = apply { this.params = params } @@ -156,6 +157,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -165,47 +167,22 @@ private constructor( fun build(): InputItemListPageAsync = InputItemListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: InputItemListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (ResponseItem) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is InputItemListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is InputItemListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "InputItemListPageAsync{service=$service, params=$params, response=$response}" + "InputItemListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListParams.kt index 11ddf361f..e3f3cbd98 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/responses/inputitems/InputItemListParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable @@ -19,7 +18,7 @@ import kotlin.jvm.optionals.getOrNull /** Returns a list of input items for a given response. */ class InputItemListParams private constructor( - private val responseId: String, + private val responseId: String?, private val after: String?, private val before: String?, private val include: List?, @@ -29,7 +28,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun responseId(): String = responseId + fun responseId(): Optional = Optional.ofNullable(responseId) /** An item ID to list items after, used in pagination. */ fun after(): Optional = Optional.ofNullable(after) @@ -64,14 +63,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [InputItemListParams]. - * - * The following fields are required: - * ```java - * .responseId() - * ``` - */ + @JvmStatic fun none(): InputItemListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [InputItemListParams]. */ @JvmStatic fun builder() = Builder() } @@ -99,7 +93,10 @@ private constructor( additionalQueryParams = inputItemListParams.additionalQueryParams.toBuilder() } - fun responseId(responseId: String) = apply { this.responseId = responseId } + fun responseId(responseId: String?) = apply { this.responseId = responseId } + + /** Alias for calling [Builder.responseId] with `responseId.orElse(null)`. */ + fun responseId(responseId: Optional) = responseId(responseId.getOrNull()) /** An item ID to list items after, used in pagination. */ fun after(after: String?) = apply { this.after = after } @@ -261,17 +258,10 @@ private constructor( * Returns an immutable instance of [InputItemListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .responseId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): InputItemListParams = InputItemListParams( - checkRequired("responseId", responseId), + responseId, after, before, include?.toImmutable(), @@ -284,7 +274,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> responseId + 0 -> responseId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCancelParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCancelParams.kt index 5b2fe821b..013b5ddcc 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCancelParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCancelParams.kt @@ -4,23 +4,23 @@ package com.openai.models.uploads import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Cancels the Upload. No Parts may be added after an Upload is cancelled. */ class UploadCancelParams private constructor( - private val uploadId: String, + private val uploadId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun uploadId(): String = uploadId + fun uploadId(): Optional = Optional.ofNullable(uploadId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [UploadCancelParams]. - * - * The following fields are required: - * ```java - * .uploadId() - * ``` - */ + @JvmStatic fun none(): UploadCancelParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [UploadCancelParams]. */ @JvmStatic fun builder() = Builder() } @@ -59,7 +54,10 @@ private constructor( additionalBodyProperties = uploadCancelParams.additionalBodyProperties.toMutableMap() } - fun uploadId(uploadId: String) = apply { this.uploadId = uploadId } + fun uploadId(uploadId: String?) = apply { this.uploadId = uploadId } + + /** Alias for calling [Builder.uploadId] with `uploadId.orElse(null)`. */ + fun uploadId(uploadId: Optional) = uploadId(uploadId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -185,17 +183,10 @@ private constructor( * Returns an immutable instance of [UploadCancelParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .uploadId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): UploadCancelParams = UploadCancelParams( - checkRequired("uploadId", uploadId), + uploadId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -207,7 +198,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> uploadId + 0 -> uploadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCompleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCompleteParams.kt index 990ef1d4d..fb5603c1e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCompleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/uploads/UploadCompleteParams.kt @@ -36,13 +36,13 @@ import kotlin.jvm.optionals.getOrNull */ class UploadCompleteParams private constructor( - private val uploadId: String, + private val uploadId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun uploadId(): String = uploadId + fun uploadId(): Optional = Optional.ofNullable(uploadId) /** * The ordered list of Part IDs. @@ -90,7 +90,6 @@ private constructor( * * The following fields are required: * ```java - * .uploadId() * .partIds() * ``` */ @@ -113,7 +112,10 @@ private constructor( additionalQueryParams = uploadCompleteParams.additionalQueryParams.toBuilder() } - fun uploadId(uploadId: String) = apply { this.uploadId = uploadId } + fun uploadId(uploadId: String?) = apply { this.uploadId = uploadId } + + /** Alias for calling [Builder.uploadId] with `uploadId.orElse(null)`. */ + fun uploadId(uploadId: Optional) = uploadId(uploadId.getOrNull()) /** * Sets the entire request body. @@ -282,7 +284,6 @@ private constructor( * * The following fields are required: * ```java - * .uploadId() * .partIds() * ``` * @@ -290,7 +291,7 @@ private constructor( */ fun build(): UploadCompleteParams = UploadCompleteParams( - checkRequired("uploadId", uploadId), + uploadId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -301,7 +302,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> uploadId + 0 -> uploadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/uploads/parts/PartCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/uploads/parts/PartCreateParams.kt index a396a730a..791713e4f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/uploads/parts/PartCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/uploads/parts/PartCreateParams.kt @@ -14,8 +14,10 @@ import com.openai.errors.OpenAIInvalidDataException import java.io.InputStream import java.nio.file.Path import java.util.Objects +import java.util.Optional import kotlin.io.path.inputStream import kotlin.io.path.name +import kotlin.jvm.optionals.getOrNull /** * Adds a [Part](https://platform.openai.com/docs/api-reference/uploads/part-object) to an @@ -29,13 +31,13 @@ import kotlin.io.path.name */ class PartCreateParams private constructor( - private val uploadId: String, + private val uploadId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun uploadId(): String = uploadId + fun uploadId(): Optional = Optional.ofNullable(uploadId) /** * The chunk of bytes for this Part. @@ -65,7 +67,6 @@ private constructor( * * The following fields are required: * ```java - * .uploadId() * .data() * ``` */ @@ -88,7 +89,10 @@ private constructor( additionalQueryParams = partCreateParams.additionalQueryParams.toBuilder() } - fun uploadId(uploadId: String) = apply { this.uploadId = uploadId } + fun uploadId(uploadId: String?) = apply { this.uploadId = uploadId } + + /** Alias for calling [Builder.uploadId] with `uploadId.orElse(null)`. */ + fun uploadId(uploadId: Optional) = uploadId(uploadId.getOrNull()) /** * Sets the entire request body. @@ -222,7 +226,6 @@ private constructor( * * The following fields are required: * ```java - * .uploadId() * .data() * ``` * @@ -230,7 +233,7 @@ private constructor( */ fun build(): PartCreateParams = PartCreateParams( - checkRequired("uploadId", uploadId), + uploadId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -241,7 +244,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> uploadId + 0 -> uploadId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreDeleteParams.kt index efd70d98d..b6bbda6ea 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreDeleteParams.kt @@ -4,23 +4,23 @@ package com.openai.models.vectorstores import com.openai.core.JsonValue import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Delete a vector store. */ class VectorStoreDeleteParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -32,14 +32,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [VectorStoreDeleteParams]. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - */ + @JvmStatic fun none(): VectorStoreDeleteParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [VectorStoreDeleteParams]. */ @JvmStatic fun builder() = Builder() } @@ -60,7 +55,11 @@ private constructor( vectorStoreDeleteParams.additionalBodyProperties.toMutableMap() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -186,17 +185,10 @@ private constructor( * Returns an immutable instance of [VectorStoreDeleteParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): VectorStoreDeleteParams = VectorStoreDeleteParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -208,7 +200,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPage.kt index fcb7958e9..52852ddb2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.vectorstores +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.VectorStoreService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [VectorStoreService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: VectorStoreService, private val params: VectorStoreListParams, private val response: VectorStoreListPageResponse, -) { +) : Page { /** * Delegates to [VectorStoreListPageResponse], but gracefully handles missing data. @@ -32,19 +32,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): VectorStoreListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): VectorStoreListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): VectorStoreListParams = params @@ -113,25 +110,6 @@ private constructor( ) } - class AutoPager(private val firstPage: VectorStoreListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPageAsync.kt index 1e2daf96a..785cf9973 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.vectorstores +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.VectorStoreServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [VectorStoreServiceAsync.list] */ class VectorStoreListPageAsync private constructor( private val service: VectorStoreServiceAsync, + private val streamHandlerExecutor: Executor, private val params: VectorStoreListParams, private val response: VectorStoreListPageResponse, -) { +) : PageAsync { /** * Delegates to [VectorStoreListPageResponse], but gracefully handles missing data. @@ -33,22 +35,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): VectorStoreListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): VectorStoreListParams = params @@ -66,6 +63,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -77,18 +75,24 @@ private constructor( class Builder internal constructor() { private var service: VectorStoreServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: VectorStoreListParams? = null private var response: VectorStoreListPageResponse? = null @JvmSynthetic internal fun from(vectorStoreListPageAsync: VectorStoreListPageAsync) = apply { service = vectorStoreListPageAsync.service + streamHandlerExecutor = vectorStoreListPageAsync.streamHandlerExecutor params = vectorStoreListPageAsync.params response = vectorStoreListPageAsync.response } fun service(service: VectorStoreServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: VectorStoreListParams) = apply { this.params = params } @@ -103,6 +107,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -112,47 +117,22 @@ private constructor( fun build(): VectorStoreListPageAsync = VectorStoreListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: VectorStoreListPageAsync) { - - fun forEach(action: Predicate, executor: Executor): CompletableFuture { - fun CompletableFuture>.forEach( - action: (VectorStore) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is VectorStoreListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is VectorStoreListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "VectorStoreListPageAsync{service=$service, params=$params, response=$response}" + "VectorStoreListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreRetrieveParams.kt index f8fc087de..87d3f482c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreRetrieveParams.kt @@ -3,20 +3,21 @@ package com.openai.models.vectorstores import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves a vector store. */ class VectorStoreRetrieveParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) fun _additionalHeaders(): Headers = additionalHeaders @@ -26,13 +27,10 @@ private constructor( companion object { + @JvmStatic fun none(): VectorStoreRetrieveParams = builder().build() + /** * Returns a mutable builder for constructing an instance of [VectorStoreRetrieveParams]. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` */ @JvmStatic fun builder() = Builder() } @@ -51,7 +49,11 @@ private constructor( additionalQueryParams = vectorStoreRetrieveParams.additionalQueryParams.toBuilder() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -155,17 +157,10 @@ private constructor( * Returns an immutable instance of [VectorStoreRetrieveParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): VectorStoreRetrieveParams = VectorStoreRetrieveParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -173,7 +168,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPage.kt index fcdefb6c5..a45345a06 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPage.kt @@ -2,13 +2,12 @@ package com.openai.models.vectorstores +import com.openai.core.AutoPager import com.openai.core.JsonValue +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.VectorStoreService import java.util.Objects -import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [VectorStoreService.search] */ @@ -17,7 +16,7 @@ private constructor( private val service: VectorStoreService, private val params: VectorStoreSearchParams, private val response: VectorStoreSearchPageResponse, -) { +) : Page { /** * Delegates to [VectorStoreSearchPageResponse], but gracefully handles missing data. @@ -30,14 +29,16 @@ private constructor( /** @see [VectorStoreSearchPageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): Optional = - getNextPageParams().map { service.search(it) } + fun nextPageParams(): VectorStoreSearchParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): VectorStoreSearchPage = service.search(nextPageParams()) + + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): VectorStoreSearchParams = params @@ -106,26 +107,6 @@ private constructor( ) } - class AutoPager(private val firstPage: VectorStoreSearchPage) : - Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPageAsync.kt index 0b7c1d85c..00431ef94 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchPageAsync.kt @@ -2,23 +2,24 @@ package com.openai.models.vectorstores +import com.openai.core.AutoPagerAsync import com.openai.core.JsonValue +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.VectorStoreServiceAsync import java.util.Objects -import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [VectorStoreServiceAsync.search] */ class VectorStoreSearchPageAsync private constructor( private val service: VectorStoreServiceAsync, + private val streamHandlerExecutor: Executor, private val params: VectorStoreSearchParams, private val response: VectorStoreSearchPageResponse, -) { +) : PageAsync { /** * Delegates to [VectorStoreSearchPageResponse], but gracefully handles missing data. @@ -31,16 +32,18 @@ private constructor( /** @see [VectorStoreSearchPageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.search(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + fun nextPageParams(): VectorStoreSearchParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): CompletableFuture = + service.search(nextPageParams()) + + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): VectorStoreSearchParams = params @@ -58,6 +61,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -69,18 +73,24 @@ private constructor( class Builder internal constructor() { private var service: VectorStoreServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: VectorStoreSearchParams? = null private var response: VectorStoreSearchPageResponse? = null @JvmSynthetic internal fun from(vectorStoreSearchPageAsync: VectorStoreSearchPageAsync) = apply { service = vectorStoreSearchPageAsync.service + streamHandlerExecutor = vectorStoreSearchPageAsync.streamHandlerExecutor params = vectorStoreSearchPageAsync.params response = vectorStoreSearchPageAsync.response } fun service(service: VectorStoreServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: VectorStoreSearchParams) = apply { this.params = params } @@ -95,6 +105,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -104,50 +115,22 @@ private constructor( fun build(): VectorStoreSearchPageAsync = VectorStoreSearchPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: VectorStoreSearchPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (VectorStoreSearchResponse) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is VectorStoreSearchPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is VectorStoreSearchPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "VectorStoreSearchPageAsync{service=$service, params=$params, response=$response}" + "VectorStoreSearchPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchParams.kt index 849e5ab3d..0add3f175 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreSearchParams.kt @@ -37,13 +37,13 @@ import kotlin.jvm.optionals.getOrNull /** Search a vector store for relevant chunks based on a query and file attributes filter. */ class VectorStoreSearchParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) /** * A query string for a search @@ -135,7 +135,6 @@ private constructor( * * The following fields are required: * ```java - * .vectorStoreId() * .query() * ``` */ @@ -158,7 +157,11 @@ private constructor( additionalQueryParams = vectorStoreSearchParams.additionalQueryParams.toBuilder() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) /** * Sets the entire request body. @@ -379,7 +382,6 @@ private constructor( * * The following fields are required: * ```java - * .vectorStoreId() * .query() * ``` * @@ -387,7 +389,7 @@ private constructor( */ fun build(): VectorStoreSearchParams = VectorStoreSearchParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -398,7 +400,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreUpdateParams.kt index e28e249ac..905256cb2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/VectorStoreUpdateParams.kt @@ -24,13 +24,13 @@ import kotlin.jvm.optionals.getOrNull /** Modifies a vector store. */ class VectorStoreUpdateParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) /** * The expiration policy for a vector store. @@ -92,14 +92,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [VectorStoreUpdateParams]. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - */ + @JvmStatic fun none(): VectorStoreUpdateParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [VectorStoreUpdateParams]. */ @JvmStatic fun builder() = Builder() } @@ -119,7 +114,11 @@ private constructor( additionalQueryParams = vectorStoreUpdateParams.additionalQueryParams.toBuilder() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) /** * Sets the entire request body. @@ -307,17 +306,10 @@ private constructor( * Returns an immutable instance of [VectorStoreUpdateParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): VectorStoreUpdateParams = VectorStoreUpdateParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -328,7 +320,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCancelParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCancelParams.kt index 1cc885126..e317488b1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCancelParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCancelParams.kt @@ -10,6 +10,7 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Cancel a vector store file batch. This attempts to cancel the processing of files in this batch @@ -18,7 +19,7 @@ import java.util.Optional class FileBatchCancelParams private constructor( private val vectorStoreId: String, - private val batchId: String, + private val batchId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -26,7 +27,7 @@ private constructor( fun vectorStoreId(): String = vectorStoreId - fun batchId(): String = batchId + fun batchId(): Optional = Optional.ofNullable(batchId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -44,7 +45,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .batchId() * ``` */ @JvmStatic fun builder() = Builder() @@ -70,7 +70,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun batchId(batchId: String) = apply { this.batchId = batchId } + fun batchId(batchId: String?) = apply { this.batchId = batchId } + + /** Alias for calling [Builder.batchId] with `batchId.orElse(null)`. */ + fun batchId(batchId: Optional) = batchId(batchId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -200,7 +203,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .batchId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -208,7 +210,7 @@ private constructor( fun build(): FileBatchCancelParams = FileBatchCancelParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("batchId", batchId), + batchId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -221,7 +223,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> batchId + 1 -> batchId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCreateParams.kt index 6109a4f18..e515321c0 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchCreateParams.kt @@ -29,13 +29,13 @@ import kotlin.jvm.optionals.getOrNull /** Create a vector store file batch. */ class FileBatchCreateParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) /** * A list of [File](https://platform.openai.com/docs/api-reference/files) IDs that the vector @@ -103,7 +103,6 @@ private constructor( * * The following fields are required: * ```java - * .vectorStoreId() * .fileIds() * ``` */ @@ -126,7 +125,11 @@ private constructor( additionalQueryParams = fileBatchCreateParams.additionalQueryParams.toBuilder() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) /** * Sets the entire request body. @@ -349,7 +352,6 @@ private constructor( * * The following fields are required: * ```java - * .vectorStoreId() * .fileIds() * ``` * @@ -357,7 +359,7 @@ private constructor( */ fun build(): FileBatchCreateParams = FileBatchCreateParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -368,7 +370,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPage.kt index 42d724d50..96a6d8b35 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPage.kt @@ -2,13 +2,13 @@ package com.openai.models.vectorstores.filebatches +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.models.vectorstores.files.VectorStoreFile import com.openai.services.blocking.vectorstores.FileBatchService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [FileBatchService.listFiles] */ @@ -17,7 +17,7 @@ private constructor( private val service: FileBatchService, private val params: FileBatchListFilesParams, private val response: FileBatchListFilesPageResponse, -) { +) : Page { /** * Delegates to [FileBatchListFilesPageResponse], but gracefully handles missing data. @@ -34,20 +34,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): FileBatchListFilesParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = - getNextPageParams().map { service.listFiles(it) } + override fun nextPage(): FileBatchListFilesPage = service.listFiles(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): FileBatchListFilesParams = params @@ -116,25 +112,6 @@ private constructor( ) } - class AutoPager(private val firstPage: FileBatchListFilesPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPageAsync.kt index 7c52c45ba..c6ea04c1f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesPageAsync.kt @@ -2,6 +2,8 @@ package com.openai.models.vectorstores.filebatches +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.models.vectorstores.files.VectorStoreFile import com.openai.services.async.vectorstores.FileBatchServiceAsync @@ -9,16 +11,16 @@ import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [FileBatchServiceAsync.listFiles] */ class FileBatchListFilesPageAsync private constructor( private val service: FileBatchServiceAsync, + private val streamHandlerExecutor: Executor, private val params: FileBatchListFilesParams, private val response: FileBatchListFilesPageResponse, -) { +) : PageAsync { /** * Delegates to [FileBatchListFilesPageResponse], but gracefully handles missing data. @@ -35,22 +37,18 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): FileBatchListFilesParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.listFiles(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = + service.listFiles(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): FileBatchListFilesParams = params @@ -68,6 +66,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -79,18 +78,24 @@ private constructor( class Builder internal constructor() { private var service: FileBatchServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: FileBatchListFilesParams? = null private var response: FileBatchListFilesPageResponse? = null @JvmSynthetic internal fun from(fileBatchListFilesPageAsync: FileBatchListFilesPageAsync) = apply { service = fileBatchListFilesPageAsync.service + streamHandlerExecutor = fileBatchListFilesPageAsync.streamHandlerExecutor params = fileBatchListFilesPageAsync.params response = fileBatchListFilesPageAsync.response } fun service(service: FileBatchServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: FileBatchListFilesParams) = apply { this.params = params } @@ -105,6 +110,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -114,50 +120,22 @@ private constructor( fun build(): FileBatchListFilesPageAsync = FileBatchListFilesPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: FileBatchListFilesPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (VectorStoreFile) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is FileBatchListFilesPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is FileBatchListFilesPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "FileBatchListFilesPageAsync{service=$service, params=$params, response=$response}" + "FileBatchListFilesPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesParams.kt index 2be57ce8b..e0b95a1db 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchListFilesParams.kt @@ -18,7 +18,7 @@ import kotlin.jvm.optionals.getOrNull class FileBatchListFilesParams private constructor( private val vectorStoreId: String, - private val batchId: String, + private val batchId: String?, private val after: String?, private val before: String?, private val filter: Filter?, @@ -30,7 +30,7 @@ private constructor( fun vectorStoreId(): String = vectorStoreId - fun batchId(): String = batchId + fun batchId(): Optional = Optional.ofNullable(batchId) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the list. @@ -75,7 +75,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .batchId() * ``` */ @JvmStatic fun builder() = Builder() @@ -109,7 +108,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun batchId(batchId: String) = apply { this.batchId = batchId } + fun batchId(batchId: String?) = apply { this.batchId = batchId } + + /** Alias for calling [Builder.batchId] with `batchId.orElse(null)`. */ + fun batchId(batchId: Optional) = batchId(batchId.getOrNull()) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the @@ -270,7 +272,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .batchId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -278,7 +279,7 @@ private constructor( fun build(): FileBatchListFilesParams = FileBatchListFilesParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("batchId", batchId), + batchId, after, before, filter, @@ -292,7 +293,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> batchId + 1 -> batchId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchRetrieveParams.kt index de2b16bd8..8a3acc77b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/filebatches/FileBatchRetrieveParams.kt @@ -7,19 +7,21 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves a vector store file batch. */ class FileBatchRetrieveParams private constructor( private val vectorStoreId: String, - private val batchId: String, + private val batchId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun vectorStoreId(): String = vectorStoreId - fun batchId(): String = batchId + fun batchId(): Optional = Optional.ofNullable(batchId) fun _additionalHeaders(): Headers = additionalHeaders @@ -35,7 +37,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .batchId() * ``` */ @JvmStatic fun builder() = Builder() @@ -59,7 +60,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun batchId(batchId: String) = apply { this.batchId = batchId } + fun batchId(batchId: String?) = apply { this.batchId = batchId } + + /** Alias for calling [Builder.batchId] with `batchId.orElse(null)`. */ + fun batchId(batchId: Optional) = batchId(batchId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -167,7 +171,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .batchId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -175,7 +178,7 @@ private constructor( fun build(): FileBatchRetrieveParams = FileBatchRetrieveParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("batchId", batchId), + batchId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -184,7 +187,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> batchId + 1 -> batchId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPage.kt index 6bbd30842..e1980ef93 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPage.kt @@ -2,13 +2,12 @@ package com.openai.models.vectorstores.files +import com.openai.core.AutoPager import com.openai.core.JsonValue +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.vectorstores.FileService import java.util.Objects -import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [FileService.content] */ @@ -17,7 +16,7 @@ private constructor( private val service: FileService, private val params: FileContentParams, private val response: FileContentPageResponse, -) { +) : Page { /** * Delegates to [FileContentPageResponse], but gracefully handles missing data. @@ -30,13 +29,16 @@ private constructor( /** @see [FileContentPageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): Optional = getNextPageParams().map { service.content(it) } + fun nextPageParams(): FileContentParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): FileContentPage = service.content(nextPageParams()) + + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): FileContentParams = params @@ -105,25 +107,6 @@ private constructor( ) } - class AutoPager(private val firstPage: FileContentPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPageAsync.kt index a55657f17..30fb9db26 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentPageAsync.kt @@ -2,23 +2,24 @@ package com.openai.models.vectorstores.files +import com.openai.core.AutoPagerAsync import com.openai.core.JsonValue +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.vectorstores.FileServiceAsync import java.util.Objects -import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [FileServiceAsync.content] */ class FileContentPageAsync private constructor( private val service: FileServiceAsync, + private val streamHandlerExecutor: Executor, private val params: FileContentParams, private val response: FileContentPageResponse, -) { +) : PageAsync { /** * Delegates to [FileContentPageResponse], but gracefully handles missing data. @@ -31,16 +32,18 @@ private constructor( /** @see [FileContentPageResponse.object_] */ fun object_(): JsonValue = response._object_() - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional = Optional.empty() + override fun hasNextPage(): Boolean = items().isNotEmpty() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.content(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + fun nextPageParams(): FileContentParams = + throw IllegalStateException("Cannot construct next page params") - fun autoPager(): AutoPager = AutoPager(this) + override fun nextPage(): CompletableFuture = + service.content(nextPageParams()) + + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): FileContentParams = params @@ -58,6 +61,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -69,18 +73,24 @@ private constructor( class Builder internal constructor() { private var service: FileServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: FileContentParams? = null private var response: FileContentPageResponse? = null @JvmSynthetic internal fun from(fileContentPageAsync: FileContentPageAsync) = apply { service = fileContentPageAsync.service + streamHandlerExecutor = fileContentPageAsync.streamHandlerExecutor params = fileContentPageAsync.params response = fileContentPageAsync.response } fun service(service: FileServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: FileContentParams) = apply { this.params = params } @@ -95,6 +105,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -104,50 +115,22 @@ private constructor( fun build(): FileContentPageAsync = FileContentPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: FileContentPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (FileContentResponse) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is FileContentPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is FileContentPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "FileContentPageAsync{service=$service, params=$params, response=$response}" + "FileContentPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentParams.kt index e52fe40d0..245032132 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileContentParams.kt @@ -7,19 +7,21 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieve the parsed contents of a vector store file. */ class FileContentParams private constructor( private val vectorStoreId: String, - private val fileId: String, + private val fileId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun vectorStoreId(): String = vectorStoreId - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) fun _additionalHeaders(): Headers = additionalHeaders @@ -35,7 +37,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * ``` */ @JvmStatic fun builder() = Builder() @@ -59,7 +60,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -167,7 +171,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -175,7 +178,7 @@ private constructor( fun build(): FileContentParams = FileContentParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("fileId", fileId), + fileId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -184,7 +187,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> fileId + 1 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileCreateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileCreateParams.kt index 339559a04..d6c0af37a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileCreateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileCreateParams.kt @@ -32,13 +32,13 @@ import kotlin.jvm.optionals.getOrNull */ class FileCreateParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) /** * A [File](https://platform.openai.com/docs/api-reference/files) ID that the vector store @@ -106,7 +106,6 @@ private constructor( * * The following fields are required: * ```java - * .vectorStoreId() * .fileId() * ``` */ @@ -129,7 +128,11 @@ private constructor( additionalQueryParams = fileCreateParams.additionalQueryParams.toBuilder() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) /** * Sets the entire request body. @@ -344,7 +347,6 @@ private constructor( * * The following fields are required: * ```java - * .vectorStoreId() * .fileId() * ``` * @@ -352,7 +354,7 @@ private constructor( */ fun build(): FileCreateParams = FileCreateParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -363,7 +365,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileDeleteParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileDeleteParams.kt index 7ac510f21..c739cb626 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileDeleteParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileDeleteParams.kt @@ -10,6 +10,7 @@ import com.openai.core.http.QueryParams import com.openai.core.toImmutable import java.util.Objects import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** * Delete a vector store file. This will remove the file from the vector store but the file itself @@ -19,7 +20,7 @@ import java.util.Optional class FileDeleteParams private constructor( private val vectorStoreId: String, - private val fileId: String, + private val fileId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, private val additionalBodyProperties: Map, @@ -27,7 +28,7 @@ private constructor( fun vectorStoreId(): String = vectorStoreId - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) fun _additionalBodyProperties(): Map = additionalBodyProperties @@ -45,7 +46,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * ``` */ @JvmStatic fun builder() = Builder() @@ -71,7 +71,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -201,7 +204,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -209,7 +211,7 @@ private constructor( fun build(): FileDeleteParams = FileDeleteParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("fileId", fileId), + fileId, additionalHeaders.build(), additionalQueryParams.build(), additionalBodyProperties.toImmutable(), @@ -222,7 +224,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> fileId + 1 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPage.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPage.kt index 51c032618..d77b54c03 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPage.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPage.kt @@ -2,12 +2,12 @@ package com.openai.models.vectorstores.files +import com.openai.core.AutoPager +import com.openai.core.Page import com.openai.core.checkRequired import com.openai.services.blocking.vectorstores.FileService import java.util.Objects import java.util.Optional -import java.util.stream.Stream -import java.util.stream.StreamSupport import kotlin.jvm.optionals.getOrNull /** @see [FileService.list] */ @@ -16,7 +16,7 @@ private constructor( private val service: FileService, private val params: FileListParams, private val response: FileListPageResponse, -) { +) : Page { /** * Delegates to [FileListPageResponse], but gracefully handles missing data. @@ -33,19 +33,16 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): FileListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): Optional = getNextPageParams().map { service.list(it) } + override fun nextPage(): FileListPage = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPager = AutoPager.from(this) /** The parameters that were used to request this page. */ fun params(): FileListParams = params @@ -114,25 +111,6 @@ private constructor( ) } - class AutoPager(private val firstPage: FileListPage) : Iterable { - - override fun iterator(): Iterator = iterator { - var page = firstPage - var index = 0 - while (true) { - while (index < page.data().size) { - yield(page.data()[index++]) - } - page = page.getNextPage().getOrNull() ?: break - index = 0 - } - } - - fun stream(): Stream { - return StreamSupport.stream(spliterator(), false) - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPageAsync.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPageAsync.kt index ace12328d..f4211867e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPageAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListPageAsync.kt @@ -2,22 +2,24 @@ package com.openai.models.vectorstores.files +import com.openai.core.AutoPagerAsync +import com.openai.core.PageAsync import com.openai.core.checkRequired import com.openai.services.async.vectorstores.FileServiceAsync import java.util.Objects import java.util.Optional import java.util.concurrent.CompletableFuture import java.util.concurrent.Executor -import java.util.function.Predicate import kotlin.jvm.optionals.getOrNull /** @see [FileServiceAsync.list] */ class FileListPageAsync private constructor( private val service: FileServiceAsync, + private val streamHandlerExecutor: Executor, private val params: FileListParams, private val response: FileListPageResponse, -) { +) : PageAsync { /** * Delegates to [FileListPageResponse], but gracefully handles missing data. @@ -34,22 +36,17 @@ private constructor( */ fun hasMore(): Optional = response._hasMore().getOptional("has_more") - fun hasNextPage(): Boolean = data().isNotEmpty() + override fun items(): List = data() - fun getNextPageParams(): Optional { - if (!hasNextPage()) { - return Optional.empty() - } + override fun hasNextPage(): Boolean = items().isNotEmpty() - return Optional.of(params.toBuilder().after(data().last()._id().getOptional("id")).build()) - } + fun nextPageParams(): FileListParams = + params.toBuilder().after(items().last()._id().getOptional("id")).build() - fun getNextPage(): CompletableFuture> = - getNextPageParams() - .map { service.list(it).thenApply { Optional.of(it) } } - .orElseGet { CompletableFuture.completedFuture(Optional.empty()) } + override fun nextPage(): CompletableFuture = service.list(nextPageParams()) - fun autoPager(): AutoPager = AutoPager(this) + fun autoPager(): AutoPagerAsync = + AutoPagerAsync.from(this, streamHandlerExecutor) /** The parameters that were used to request this page. */ fun params(): FileListParams = params @@ -67,6 +64,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -78,18 +76,24 @@ private constructor( class Builder internal constructor() { private var service: FileServiceAsync? = null + private var streamHandlerExecutor: Executor? = null private var params: FileListParams? = null private var response: FileListPageResponse? = null @JvmSynthetic internal fun from(fileListPageAsync: FileListPageAsync) = apply { service = fileListPageAsync.service + streamHandlerExecutor = fileListPageAsync.streamHandlerExecutor params = fileListPageAsync.params response = fileListPageAsync.response } fun service(service: FileServiceAsync) = apply { this.service = service } + fun streamHandlerExecutor(streamHandlerExecutor: Executor) = apply { + this.streamHandlerExecutor = streamHandlerExecutor + } + /** The parameters that were used to request this page. */ fun params(params: FileListParams) = apply { this.params = params } @@ -104,6 +108,7 @@ private constructor( * The following fields are required: * ```java * .service() + * .streamHandlerExecutor() * .params() * .response() * ``` @@ -113,50 +118,22 @@ private constructor( fun build(): FileListPageAsync = FileListPageAsync( checkRequired("service", service), + checkRequired("streamHandlerExecutor", streamHandlerExecutor), checkRequired("params", params), checkRequired("response", response), ) } - class AutoPager(private val firstPage: FileListPageAsync) { - - fun forEach( - action: Predicate, - executor: Executor, - ): CompletableFuture { - fun CompletableFuture>.forEach( - action: (VectorStoreFile) -> Boolean, - executor: Executor, - ): CompletableFuture = - thenComposeAsync( - { page -> - page - .filter { it.data().all(action) } - .map { it.getNextPage().forEach(action, executor) } - .orElseGet { CompletableFuture.completedFuture(null) } - }, - executor, - ) - return CompletableFuture.completedFuture(Optional.of(firstPage)) - .forEach(action::test, executor) - } - - fun toList(executor: Executor): CompletableFuture> { - val values = mutableListOf() - return forEach(values::add, executor).thenApply { values } - } - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return /* spotless:off */ other is FileListPageAsync && service == other.service && params == other.params && response == other.response /* spotless:on */ + return /* spotless:off */ other is FileListPageAsync && service == other.service && streamHandlerExecutor == other.streamHandlerExecutor && params == other.params && response == other.response /* spotless:on */ } - override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, params, response) /* spotless:on */ + override fun hashCode(): Int = /* spotless:off */ Objects.hash(service, streamHandlerExecutor, params, response) /* spotless:on */ override fun toString() = - "FileListPageAsync{service=$service, params=$params, response=$response}" + "FileListPageAsync{service=$service, streamHandlerExecutor=$streamHandlerExecutor, params=$params, response=$response}" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListParams.kt index 4f0240de9..c2ca930cd 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileListParams.kt @@ -6,7 +6,6 @@ import com.fasterxml.jackson.annotation.JsonCreator import com.openai.core.Enum import com.openai.core.JsonField import com.openai.core.Params -import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import com.openai.errors.OpenAIInvalidDataException @@ -17,7 +16,7 @@ import kotlin.jvm.optionals.getOrNull /** Returns a list of vector store files. */ class FileListParams private constructor( - private val vectorStoreId: String, + private val vectorStoreId: String?, private val after: String?, private val before: String?, private val filter: Filter?, @@ -27,7 +26,7 @@ private constructor( private val additionalQueryParams: QueryParams, ) : Params { - fun vectorStoreId(): String = vectorStoreId + fun vectorStoreId(): Optional = Optional.ofNullable(vectorStoreId) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the list. @@ -66,14 +65,9 @@ private constructor( companion object { - /** - * Returns a mutable builder for constructing an instance of [FileListParams]. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - */ + @JvmStatic fun none(): FileListParams = builder().build() + + /** Returns a mutable builder for constructing an instance of [FileListParams]. */ @JvmStatic fun builder() = Builder() } @@ -101,7 +95,11 @@ private constructor( additionalQueryParams = fileListParams.additionalQueryParams.toBuilder() } - fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } + fun vectorStoreId(vectorStoreId: String?) = apply { this.vectorStoreId = vectorStoreId } + + /** Alias for calling [Builder.vectorStoreId] with `vectorStoreId.orElse(null)`. */ + fun vectorStoreId(vectorStoreId: Optional) = + vectorStoreId(vectorStoreId.getOrNull()) /** * A cursor for use in pagination. `after` is an object ID that defines your place in the @@ -258,17 +256,10 @@ private constructor( * Returns an immutable instance of [FileListParams]. * * Further updates to this [Builder] will not mutate the returned instance. - * - * The following fields are required: - * ```java - * .vectorStoreId() - * ``` - * - * @throws IllegalStateException if any required field is unset. */ fun build(): FileListParams = FileListParams( - checkRequired("vectorStoreId", vectorStoreId), + vectorStoreId, after, before, filter, @@ -281,7 +272,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { - 0 -> vectorStoreId + 0 -> vectorStoreId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileRetrieveParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileRetrieveParams.kt index 5ab124552..f81b11273 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileRetrieveParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileRetrieveParams.kt @@ -7,19 +7,21 @@ import com.openai.core.checkRequired import com.openai.core.http.Headers import com.openai.core.http.QueryParams import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull /** Retrieves a vector store file. */ class FileRetrieveParams private constructor( private val vectorStoreId: String, - private val fileId: String, + private val fileId: String?, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, ) : Params { fun vectorStoreId(): String = vectorStoreId - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) fun _additionalHeaders(): Headers = additionalHeaders @@ -35,7 +37,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * ``` */ @JvmStatic fun builder() = Builder() @@ -59,7 +60,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) fun additionalHeaders(additionalHeaders: Headers) = apply { this.additionalHeaders.clear() @@ -167,7 +171,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * ``` * * @throws IllegalStateException if any required field is unset. @@ -175,7 +178,7 @@ private constructor( fun build(): FileRetrieveParams = FileRetrieveParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("fileId", fileId), + fileId, additionalHeaders.build(), additionalQueryParams.build(), ) @@ -184,7 +187,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> fileId + 1 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileUpdateParams.kt b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileUpdateParams.kt index c5dbccbde..2377d4d26 100644 --- a/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileUpdateParams.kt +++ b/openai-java-core/src/main/kotlin/com/openai/models/vectorstores/files/FileUpdateParams.kt @@ -25,7 +25,7 @@ import kotlin.jvm.optionals.getOrNull class FileUpdateParams private constructor( private val vectorStoreId: String, - private val fileId: String, + private val fileId: String?, private val body: Body, private val additionalHeaders: Headers, private val additionalQueryParams: QueryParams, @@ -33,7 +33,7 @@ private constructor( fun vectorStoreId(): String = vectorStoreId - fun fileId(): String = fileId + fun fileId(): Optional = Optional.ofNullable(fileId) /** * Set of 16 key-value pairs that can be attached to an object. This can be useful for storing @@ -69,7 +69,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * .attributes() * ``` */ @@ -96,7 +95,10 @@ private constructor( fun vectorStoreId(vectorStoreId: String) = apply { this.vectorStoreId = vectorStoreId } - fun fileId(fileId: String) = apply { this.fileId = fileId } + fun fileId(fileId: String?) = apply { this.fileId = fileId } + + /** Alias for calling [Builder.fileId] with `fileId.orElse(null)`. */ + fun fileId(fileId: Optional) = fileId(fileId.getOrNull()) /** * Sets the entire request body. @@ -253,7 +255,6 @@ private constructor( * The following fields are required: * ```java * .vectorStoreId() - * .fileId() * .attributes() * ``` * @@ -262,7 +263,7 @@ private constructor( fun build(): FileUpdateParams = FileUpdateParams( checkRequired("vectorStoreId", vectorStoreId), - checkRequired("fileId", fileId), + fileId, body.build(), additionalHeaders.build(), additionalQueryParams.build(), @@ -274,7 +275,7 @@ private constructor( fun _pathParam(index: Int): String = when (index) { 0 -> vectorStoreId - 1 -> fileId + 1 -> fileId ?: "" else -> "" } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsync.kt index 45dd0c246..84bc4043c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsync.kt @@ -31,8 +31,22 @@ interface BatchServiceAsync { ): CompletableFuture /** Retrieves a batch. */ - fun retrieve(params: BatchRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(batchId: String): CompletableFuture = + retrieve(batchId, BatchRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + ): CompletableFuture = retrieve(batchId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -40,6 +54,14 @@ interface BatchServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: BatchRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(batchId: String, requestOptions: RequestOptions): CompletableFuture = + retrieve(batchId, BatchRetrieveParams.none(), requestOptions) + /** List your organization's batches. */ fun list(): CompletableFuture = list(BatchListParams.none()) @@ -63,8 +85,22 @@ interface BatchServiceAsync { * before changing to `cancelled`, where it will have partial results (if any) available in the * output file. */ - fun cancel(params: BatchCancelParams): CompletableFuture = - cancel(params, RequestOptions.none()) + fun cancel(batchId: String): CompletableFuture = + cancel(batchId, BatchCancelParams.none()) + + /** @see [cancel] */ + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + ): CompletableFuture = cancel(batchId, params, RequestOptions.none()) /** @see [cancel] */ fun cancel( @@ -72,6 +108,14 @@ interface BatchServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [cancel] */ + fun cancel(params: BatchCancelParams): CompletableFuture = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel(batchId: String, requestOptions: RequestOptions): CompletableFuture = + cancel(batchId, BatchCancelParams.none(), requestOptions) + /** A view of [BatchServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -95,8 +139,25 @@ interface BatchServiceAsync { * [BatchServiceAsync.retrieve]. */ @MustBeClosed - fun retrieve(params: BatchRetrieveParams): CompletableFuture> = - retrieve(params, RequestOptions.none()) + fun retrieve(batchId: String): CompletableFuture> = + retrieve(batchId, BatchRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + ): CompletableFuture> = + retrieve(batchId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -105,6 +166,19 @@ interface BatchServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: BatchRetrieveParams): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(batchId, BatchRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /batches`, but is otherwise the same as * [BatchServiceAsync.list]. @@ -139,8 +213,25 @@ interface BatchServiceAsync { * same as [BatchServiceAsync.cancel]. */ @MustBeClosed - fun cancel(params: BatchCancelParams): CompletableFuture> = - cancel(params, RequestOptions.none()) + fun cancel(batchId: String): CompletableFuture> = + cancel(batchId, BatchCancelParams.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + ): CompletableFuture> = + cancel(batchId, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -148,5 +239,18 @@ interface BatchServiceAsync { params: BatchCancelParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [cancel] */ + @MustBeClosed + fun cancel(params: BatchCancelParams): CompletableFuture> = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + cancel(batchId, BatchCancelParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsyncImpl.kt index 82fbc507d..bcd741103 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/BatchServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -23,6 +24,7 @@ import com.openai.models.batches.BatchListPageResponse import com.openai.models.batches.BatchListParams import com.openai.models.batches.BatchRetrieveParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class BatchServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : BatchServiceAsync { @@ -103,6 +105,9 @@ class BatchServiceAsyncImpl internal constructor(private val clientOptions: Clie params: BatchRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -154,6 +159,7 @@ class BatchServiceAsyncImpl internal constructor(private val clientOptions: Clie .let { BatchListPageAsync.builder() .service(BatchServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -169,6 +175,9 @@ class BatchServiceAsyncImpl internal constructor(private val clientOptions: Clie params: BatchCancelParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsync.kt index 8c2fad82c..d3b270753 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsync.kt @@ -44,8 +44,22 @@ interface EvalServiceAsync { ): CompletableFuture /** Get an evaluation by ID. */ - fun retrieve(params: EvalRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(evalId: String): CompletableFuture = + retrieve(evalId, EvalRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + ): CompletableFuture = retrieve(evalId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -53,9 +67,34 @@ interface EvalServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: EvalRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(evalId, EvalRetrieveParams.none(), requestOptions) + /** Update certain properties of an evaluation. */ - fun update(params: EvalUpdateParams): CompletableFuture = - update(params, RequestOptions.none()) + fun update(evalId: String): CompletableFuture = + update(evalId, EvalUpdateParams.none()) + + /** @see [update] */ + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [update] */ + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + ): CompletableFuture = update(evalId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -63,6 +102,17 @@ interface EvalServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [update] */ + fun update(params: EvalUpdateParams): CompletableFuture = + update(params, RequestOptions.none()) + + /** @see [update] */ + fun update( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + update(evalId, EvalUpdateParams.none(), requestOptions) + /** List evaluations for a project. */ fun list(): CompletableFuture = list(EvalListParams.none()) @@ -81,8 +131,22 @@ interface EvalServiceAsync { list(EvalListParams.none(), requestOptions) /** Delete an evaluation. */ - fun delete(params: EvalDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(evalId: String): CompletableFuture = + delete(evalId, EvalDeleteParams.none()) + + /** @see [delete] */ + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + ): CompletableFuture = delete(evalId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -90,6 +154,17 @@ interface EvalServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: EvalDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + delete(evalId, EvalDeleteParams.none(), requestOptions) + /** A view of [EvalServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -117,10 +192,25 @@ interface EvalServiceAsync { * [EvalServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve(evalId: String): CompletableFuture> = + retrieve(evalId, EvalRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( - params: EvalRetrieveParams + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - retrieve(params, RequestOptions.none()) + retrieve(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + ): CompletableFuture> = + retrieve(evalId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -129,15 +219,45 @@ interface EvalServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + params: EvalRetrieveParams + ): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(evalId, EvalRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /evals/{eval_id}`, but is otherwise the same as * [EvalServiceAsync.update]. */ @MustBeClosed + fun update(evalId: String): CompletableFuture> = + update(evalId, EvalUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed fun update( - params: EvalUpdateParams + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - update(params, RequestOptions.none()) + update(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + ): CompletableFuture> = + update(evalId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -146,6 +266,21 @@ interface EvalServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [update] */ + @MustBeClosed + fun update( + params: EvalUpdateParams + ): CompletableFuture> = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + update(evalId, EvalUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /evals`, but is otherwise the same as * [EvalServiceAsync.list]. @@ -180,10 +315,25 @@ interface EvalServiceAsync { * [EvalServiceAsync.delete]. */ @MustBeClosed + fun delete(evalId: String): CompletableFuture> = + delete(evalId, EvalDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed fun delete( - params: EvalDeleteParams + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - delete(params, RequestOptions.none()) + delete(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + ): CompletableFuture> = + delete(evalId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -191,5 +341,20 @@ interface EvalServiceAsync { params: EvalDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [delete] */ + @MustBeClosed + fun delete( + params: EvalDeleteParams + ): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(evalId, EvalDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsyncImpl.kt index 46b90a997..8ceac275b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/EvalServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -29,6 +30,7 @@ import com.openai.models.evals.EvalUpdateResponse import com.openai.services.async.evals.RunServiceAsync import com.openai.services.async.evals.RunServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class EvalServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : EvalServiceAsync { @@ -127,6 +129,9 @@ class EvalServiceAsyncImpl internal constructor(private val clientOptions: Clien params: EvalRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -156,6 +161,9 @@ class EvalServiceAsyncImpl internal constructor(private val clientOptions: Clien params: EvalUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -208,6 +216,7 @@ class EvalServiceAsyncImpl internal constructor(private val clientOptions: Clien .let { EvalListPageAsync.builder() .service(EvalServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -223,6 +232,9 @@ class EvalServiceAsyncImpl internal constructor(private val clientOptions: Clien params: EvalDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsync.kt index 1da62fdff..6cc13c80f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsync.kt @@ -52,8 +52,22 @@ interface FileServiceAsync { ): CompletableFuture /** Returns information about a specific file. */ - fun retrieve(params: FileRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(fileId: String): CompletableFuture = + retrieve(fileId, FileRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + ): CompletableFuture = retrieve(fileId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -61,6 +75,14 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: FileRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(fileId: String, requestOptions: RequestOptions): CompletableFuture = + retrieve(fileId, FileRetrieveParams.none(), requestOptions) + /** Returns a list of files. */ fun list(): CompletableFuture = list(FileListParams.none()) @@ -79,8 +101,22 @@ interface FileServiceAsync { list(FileListParams.none(), requestOptions) /** Delete a file. */ - fun delete(params: FileDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(fileId: String): CompletableFuture = + delete(fileId, FileDeleteParams.none()) + + /** @see [delete] */ + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + ): CompletableFuture = delete(fileId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -88,10 +124,34 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: FileDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(fileId: String, requestOptions: RequestOptions): CompletableFuture = + delete(fileId, FileDeleteParams.none(), requestOptions) + /** Returns the contents of the specified file. */ @MustBeClosed - fun content(params: FileContentParams): CompletableFuture = - content(params, RequestOptions.none()) + fun content(fileId: String): CompletableFuture = + content(fileId, FileContentParams.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + ): CompletableFuture = content(fileId, params, RequestOptions.none()) /** @see [content] */ @MustBeClosed @@ -100,6 +160,16 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [content] */ + @MustBeClosed + fun content(params: FileContentParams): CompletableFuture = + content(params, RequestOptions.none()) + + /** @see [content] */ + @MustBeClosed + fun content(fileId: String, requestOptions: RequestOptions): CompletableFuture = + content(fileId, FileContentParams.none(), requestOptions) + /** A view of [FileServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -123,8 +193,25 @@ interface FileServiceAsync { * [FileServiceAsync.retrieve]. */ @MustBeClosed - fun retrieve(params: FileRetrieveParams): CompletableFuture> = - retrieve(params, RequestOptions.none()) + fun retrieve(fileId: String): CompletableFuture> = + retrieve(fileId, FileRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + ): CompletableFuture> = + retrieve(fileId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -133,6 +220,19 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: FileRetrieveParams): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(fileId, FileRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /files`, but is otherwise the same as * [FileServiceAsync.list]. @@ -167,8 +267,25 @@ interface FileServiceAsync { * [FileServiceAsync.delete]. */ @MustBeClosed - fun delete(params: FileDeleteParams): CompletableFuture> = - delete(params, RequestOptions.none()) + fun delete(fileId: String): CompletableFuture> = + delete(fileId, FileDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + ): CompletableFuture> = + delete(fileId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -177,13 +294,42 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [delete] */ + @MustBeClosed + fun delete(params: FileDeleteParams): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(fileId, FileDeleteParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /files/{file_id}/content`, but is otherwise the same * as [FileServiceAsync.content]. */ @MustBeClosed - fun content(params: FileContentParams): CompletableFuture = - content(params, RequestOptions.none()) + fun content(fileId: String): CompletableFuture = + content(fileId, FileContentParams.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + ): CompletableFuture = content(fileId, params, RequestOptions.none()) /** @see [content] */ @MustBeClosed @@ -191,5 +337,18 @@ interface FileServiceAsync { params: FileContentParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + + /** @see [content] */ + @MustBeClosed + fun content(params: FileContentParams): CompletableFuture = + content(params, RequestOptions.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + content(fileId, FileContentParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsyncImpl.kt index a60ded873..83a8c11c1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/FileServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -27,6 +28,7 @@ import com.openai.models.files.FileListParams import com.openai.models.files.FileObject import com.openai.models.files.FileRetrieveParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class FileServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : FileServiceAsync { @@ -114,6 +116,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -165,6 +170,7 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien .let { FileListPageAsync.builder() .service(FileServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -180,6 +186,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -207,6 +216,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileContentParams, requestOptions: RequestOptions, ): CompletableFuture { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsync.kt index aaa7bc2c4..920bcfccc 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsync.kt @@ -2,8 +2,10 @@ package com.openai.services.async +import com.openai.services.async.finetuning.AlphaServiceAsync import com.openai.services.async.finetuning.CheckpointServiceAsync import com.openai.services.async.finetuning.JobServiceAsync +import com.openai.services.async.finetuning.MethodServiceAsync interface FineTuningServiceAsync { @@ -12,18 +14,26 @@ interface FineTuningServiceAsync { */ fun withRawResponse(): WithRawResponse + fun methods(): MethodServiceAsync + fun jobs(): JobServiceAsync fun checkpoints(): CheckpointServiceAsync + fun alpha(): AlphaServiceAsync + /** * A view of [FineTuningServiceAsync] that provides access to raw HTTP responses for each * method. */ interface WithRawResponse { + fun methods(): MethodServiceAsync.WithRawResponse + fun jobs(): JobServiceAsync.WithRawResponse fun checkpoints(): CheckpointServiceAsync.WithRawResponse + + fun alpha(): AlphaServiceAsync.WithRawResponse } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsyncImpl.kt index ca6f76435..59413489e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/FineTuningServiceAsyncImpl.kt @@ -3,10 +3,14 @@ package com.openai.services.async import com.openai.core.ClientOptions +import com.openai.services.async.finetuning.AlphaServiceAsync +import com.openai.services.async.finetuning.AlphaServiceAsyncImpl import com.openai.services.async.finetuning.CheckpointServiceAsync import com.openai.services.async.finetuning.CheckpointServiceAsyncImpl import com.openai.services.async.finetuning.JobServiceAsync import com.openai.services.async.finetuning.JobServiceAsyncImpl +import com.openai.services.async.finetuning.MethodServiceAsync +import com.openai.services.async.finetuning.MethodServiceAsyncImpl class FineTuningServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : FineTuningServiceAsync { @@ -15,21 +19,33 @@ class FineTuningServiceAsyncImpl internal constructor(private val clientOptions: WithRawResponseImpl(clientOptions) } + private val methods: MethodServiceAsync by lazy { MethodServiceAsyncImpl(clientOptions) } + private val jobs: JobServiceAsync by lazy { JobServiceAsyncImpl(clientOptions) } private val checkpoints: CheckpointServiceAsync by lazy { CheckpointServiceAsyncImpl(clientOptions) } + private val alpha: AlphaServiceAsync by lazy { AlphaServiceAsyncImpl(clientOptions) } + override fun withRawResponse(): FineTuningServiceAsync.WithRawResponse = withRawResponse + override fun methods(): MethodServiceAsync = methods + override fun jobs(): JobServiceAsync = jobs override fun checkpoints(): CheckpointServiceAsync = checkpoints + override fun alpha(): AlphaServiceAsync = alpha + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : FineTuningServiceAsync.WithRawResponse { + private val methods: MethodServiceAsync.WithRawResponse by lazy { + MethodServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + private val jobs: JobServiceAsync.WithRawResponse by lazy { JobServiceAsyncImpl.WithRawResponseImpl(clientOptions) } @@ -38,8 +54,16 @@ class FineTuningServiceAsyncImpl internal constructor(private val clientOptions: CheckpointServiceAsyncImpl.WithRawResponseImpl(clientOptions) } + private val alpha: AlphaServiceAsync.WithRawResponse by lazy { + AlphaServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun methods(): MethodServiceAsync.WithRawResponse = methods + override fun jobs(): JobServiceAsync.WithRawResponse = jobs override fun checkpoints(): CheckpointServiceAsync.WithRawResponse = checkpoints + + override fun alpha(): AlphaServiceAsync.WithRawResponse = alpha } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/GraderServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/GraderServiceAsync.kt new file mode 100644 index 000000000..fdc63d85b --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/GraderServiceAsync.kt @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async + +import com.openai.services.async.graders.GraderModelServiceAsync + +interface GraderServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + fun graderModels(): GraderModelServiceAsync + + /** + * A view of [GraderServiceAsync] that provides access to raw HTTP responses for each method. + */ + interface WithRawResponse { + + fun graderModels(): GraderModelServiceAsync.WithRawResponse + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/GraderServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/GraderServiceAsyncImpl.kt new file mode 100644 index 000000000..28ac64f37 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/GraderServiceAsyncImpl.kt @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async + +import com.openai.core.ClientOptions +import com.openai.services.async.graders.GraderModelServiceAsync +import com.openai.services.async.graders.GraderModelServiceAsyncImpl + +class GraderServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + GraderServiceAsync { + + private val withRawResponse: GraderServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val graderModels: GraderModelServiceAsync by lazy { + GraderModelServiceAsyncImpl(clientOptions) + } + + override fun withRawResponse(): GraderServiceAsync.WithRawResponse = withRawResponse + + override fun graderModels(): GraderModelServiceAsync = graderModels + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GraderServiceAsync.WithRawResponse { + + private val graderModels: GraderModelServiceAsync.WithRawResponse by lazy { + GraderModelServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun graderModels(): GraderModelServiceAsync.WithRawResponse = graderModels + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsync.kt index 33205d210..993f48db5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsync.kt @@ -24,8 +24,21 @@ interface ModelServiceAsync { * Retrieves a model instance, providing basic information about the model such as the owner and * permissioning. */ - fun retrieve(params: ModelRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(model: String): CompletableFuture = + retrieve(model, ModelRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = retrieve(params.toBuilder().model(model).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + ): CompletableFuture = retrieve(model, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -33,6 +46,14 @@ interface ModelServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: ModelRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(model: String, requestOptions: RequestOptions): CompletableFuture = + retrieve(model, ModelRetrieveParams.none(), requestOptions) + /** * Lists the currently available models, and provides basic information about each one such as * the owner and availability. @@ -58,8 +79,22 @@ interface ModelServiceAsync { * Delete a fine-tuned model. You must have the Owner role in your organization to delete a * model. */ - fun delete(params: ModelDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(model: String): CompletableFuture = + delete(model, ModelDeleteParams.none()) + + /** @see [delete] */ + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().model(model).build(), requestOptions) + + /** @see [delete] */ + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + ): CompletableFuture = delete(model, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -67,6 +102,14 @@ interface ModelServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: ModelDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(model: String, requestOptions: RequestOptions): CompletableFuture = + delete(model, ModelDeleteParams.none(), requestOptions) + /** A view of [ModelServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -75,8 +118,25 @@ interface ModelServiceAsync { * [ModelServiceAsync.retrieve]. */ @MustBeClosed - fun retrieve(params: ModelRetrieveParams): CompletableFuture> = - retrieve(params, RequestOptions.none()) + fun retrieve(model: String): CompletableFuture> = + retrieve(model, ModelRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().model(model).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + ): CompletableFuture> = + retrieve(model, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -85,6 +145,19 @@ interface ModelServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ModelRetrieveParams): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + model: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(model, ModelRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /models`, but is otherwise the same as * [ModelServiceAsync.list]. @@ -119,8 +192,25 @@ interface ModelServiceAsync { * [ModelServiceAsync.delete]. */ @MustBeClosed - fun delete(params: ModelDeleteParams): CompletableFuture> = - delete(params, RequestOptions.none()) + fun delete(model: String): CompletableFuture> = + delete(model, ModelDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().model(model).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + ): CompletableFuture> = + delete(model, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -128,5 +218,18 @@ interface ModelServiceAsync { params: ModelDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [delete] */ + @MustBeClosed + fun delete(params: ModelDeleteParams): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + model: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(model, ModelDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsyncImpl.kt index 7973eaa3f..9f15cdea3 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ModelServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -23,6 +24,7 @@ import com.openai.models.models.ModelListPageResponse import com.openai.models.models.ModelListParams import com.openai.models.models.ModelRetrieveParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class ModelServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ModelServiceAsync { @@ -66,12 +68,15 @@ class ModelServiceAsyncImpl internal constructor(private val clientOptions: Clie params: ModelRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("model", params.model().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) .addPathSegments("models", params._pathParam(0)) .build() - .prepareAsync(clientOptions, params, params.model()) + .prepareAsync(clientOptions, params, params.model().get()) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } @@ -117,6 +122,7 @@ class ModelServiceAsyncImpl internal constructor(private val clientOptions: Clie .let { ModelListPageAsync.builder() .service(ModelServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -132,13 +138,16 @@ class ModelServiceAsyncImpl internal constructor(private val clientOptions: Clie params: ModelDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("model", params.model().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) .addPathSegments("models", params._pathParam(0)) .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } .build() - .prepareAsync(clientOptions, params, params.model()) + .prepareAsync(clientOptions, params, params.model().get()) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) return request .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt index 34042fd28..f66149de6 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsync.kt @@ -66,8 +66,22 @@ interface ResponseServiceAsync { ): AsyncStreamResponse /** Retrieves a model response with the given ID. */ - fun retrieve(params: ResponseRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(responseId: String): CompletableFuture = + retrieve(responseId, ResponseRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + ): CompletableFuture = retrieve(responseId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -75,9 +89,31 @@ interface ResponseServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: ResponseRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(responseId: String, requestOptions: RequestOptions): CompletableFuture = + retrieve(responseId, ResponseRetrieveParams.none(), requestOptions) + /** Deletes a model response with the given ID. */ - fun delete(params: ResponseDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(responseId: String): CompletableFuture = + delete(responseId, ResponseDeleteParams.none()) + + /** @see [delete] */ + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + ): CompletableFuture = delete(responseId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -85,6 +121,14 @@ interface ResponseServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: ResponseDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(responseId: String, requestOptions: RequestOptions): CompletableFuture = + delete(responseId, ResponseDeleteParams.none(), requestOptions) + /** * A view of [ResponseServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -129,8 +173,25 @@ interface ResponseServiceAsync { * as [ResponseServiceAsync.retrieve]. */ @MustBeClosed - fun retrieve(params: ResponseRetrieveParams): CompletableFuture> = - retrieve(params, RequestOptions.none()) + fun retrieve(responseId: String): CompletableFuture> = + retrieve(responseId, ResponseRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + ): CompletableFuture> = + retrieve(responseId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -139,13 +200,42 @@ interface ResponseServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ResponseRetrieveParams): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + responseId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(responseId, ResponseRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /responses/{response_id}`, but is otherwise the * same as [ResponseServiceAsync.delete]. */ @MustBeClosed - fun delete(params: ResponseDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(responseId: String): CompletableFuture = + delete(responseId, ResponseDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + ): CompletableFuture = delete(responseId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -153,5 +243,18 @@ interface ResponseServiceAsync { params: ResponseDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + + /** @see [delete] */ + @MustBeClosed + fun delete(params: ResponseDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + responseId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + delete(responseId, ResponseDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt index 122e68f43..7f90cea5a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/ResponseServiceAsyncImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.emptyHandler import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler @@ -32,6 +33,7 @@ import com.openai.models.responses.ResponseStreamEvent import com.openai.services.async.responses.InputItemServiceAsync import com.openai.services.async.responses.InputItemServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class ResponseServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ResponseServiceAsync { @@ -170,6 +172,9 @@ class ResponseServiceAsyncImpl internal constructor(private val clientOptions: C params: ResponseRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("responseId", params.responseId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -198,6 +203,9 @@ class ResponseServiceAsyncImpl internal constructor(private val clientOptions: C params: ResponseDeleteParams, requestOptions: RequestOptions, ): CompletableFuture { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("responseId", params.responseId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsync.kt index 7e0dce0ce..98218ac53 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsync.kt @@ -51,8 +51,22 @@ interface UploadServiceAsync { ): CompletableFuture /** Cancels the Upload. No Parts may be added after an Upload is cancelled. */ - fun cancel(params: UploadCancelParams): CompletableFuture = - cancel(params, RequestOptions.none()) + fun cancel(uploadId: String): CompletableFuture = + cancel(uploadId, UploadCancelParams.none()) + + /** @see [cancel] */ + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + cancel(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [cancel] */ + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + ): CompletableFuture = cancel(uploadId, params, RequestOptions.none()) /** @see [cancel] */ fun cancel( @@ -60,6 +74,14 @@ interface UploadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [cancel] */ + fun cancel(params: UploadCancelParams): CompletableFuture = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel(uploadId: String, requestOptions: RequestOptions): CompletableFuture = + cancel(uploadId, UploadCancelParams.none(), requestOptions) + /** * Completes the [Upload](https://platform.openai.com/docs/api-reference/uploads/object). * @@ -73,6 +95,18 @@ interface UploadServiceAsync { * specified when creating the Upload object. No Parts may be added after an Upload is * completed. */ + fun complete(uploadId: String, params: UploadCompleteParams): CompletableFuture = + complete(uploadId, params, RequestOptions.none()) + + /** @see [complete] */ + fun complete( + uploadId: String, + params: UploadCompleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + complete(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [complete] */ fun complete(params: UploadCompleteParams): CompletableFuture = complete(params, RequestOptions.none()) @@ -109,8 +143,25 @@ interface UploadServiceAsync { * same as [UploadServiceAsync.cancel]. */ @MustBeClosed - fun cancel(params: UploadCancelParams): CompletableFuture> = - cancel(params, RequestOptions.none()) + fun cancel(uploadId: String): CompletableFuture> = + cancel(uploadId, UploadCancelParams.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + cancel(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + ): CompletableFuture> = + cancel(uploadId, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -119,11 +170,41 @@ interface UploadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [cancel] */ + @MustBeClosed + fun cancel(params: UploadCancelParams): CompletableFuture> = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + uploadId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + cancel(uploadId, UploadCancelParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /uploads/{upload_id}/complete`, but is otherwise * the same as [UploadServiceAsync.complete]. */ @MustBeClosed + fun complete( + uploadId: String, + params: UploadCompleteParams, + ): CompletableFuture> = + complete(uploadId, params, RequestOptions.none()) + + /** @see [complete] */ + @MustBeClosed + fun complete( + uploadId: String, + params: UploadCompleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + complete(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [complete] */ + @MustBeClosed fun complete(params: UploadCompleteParams): CompletableFuture> = complete(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsyncImpl.kt index 9877742d4..30cc034a8 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/UploadServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -22,6 +23,7 @@ import com.openai.models.uploads.UploadCreateParams import com.openai.services.async.uploads.PartServiceAsync import com.openai.services.async.uploads.PartServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class UploadServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : UploadServiceAsync { @@ -105,6 +107,9 @@ class UploadServiceAsyncImpl internal constructor(private val clientOptions: Cli params: UploadCancelParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("uploadId", params.uploadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -135,6 +140,9 @@ class UploadServiceAsyncImpl internal constructor(private val clientOptions: Cli params: UploadCompleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("uploadId", params.uploadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsync.kt index 4fb10a20a..ff07354c2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsync.kt @@ -49,8 +49,22 @@ interface VectorStoreServiceAsync { create(VectorStoreCreateParams.none(), requestOptions) /** Retrieves a vector store. */ - fun retrieve(params: VectorStoreRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(vectorStoreId: String): CompletableFuture = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + ): CompletableFuture = retrieve(vectorStoreId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -58,9 +72,34 @@ interface VectorStoreServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: VectorStoreRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none(), requestOptions) + /** Modifies a vector store. */ - fun update(params: VectorStoreUpdateParams): CompletableFuture = - update(params, RequestOptions.none()) + fun update(vectorStoreId: String): CompletableFuture = + update(vectorStoreId, VectorStoreUpdateParams.none()) + + /** @see [update] */ + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [update] */ + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + ): CompletableFuture = update(vectorStoreId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -68,6 +107,17 @@ interface VectorStoreServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [update] */ + fun update(params: VectorStoreUpdateParams): CompletableFuture = + update(params, RequestOptions.none()) + + /** @see [update] */ + fun update( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + update(vectorStoreId, VectorStoreUpdateParams.none(), requestOptions) + /** Returns a list of vector stores. */ fun list(): CompletableFuture = list(VectorStoreListParams.none()) @@ -87,8 +137,22 @@ interface VectorStoreServiceAsync { list(VectorStoreListParams.none(), requestOptions) /** Delete a vector store. */ - fun delete(params: VectorStoreDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(vectorStoreId: String): CompletableFuture = + delete(vectorStoreId, VectorStoreDeleteParams.none()) + + /** @see [delete] */ + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + ): CompletableFuture = delete(vectorStoreId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -96,7 +160,33 @@ interface VectorStoreServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: VectorStoreDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + delete(vectorStoreId, VectorStoreDeleteParams.none(), requestOptions) + /** Search a vector store for relevant chunks based on a query and file attributes filter. */ + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + ): CompletableFuture = + search(vectorStoreId, params, RequestOptions.none()) + + /** @see [search] */ + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + search(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [search] */ fun search(params: VectorStoreSearchParams): CompletableFuture = search(params, RequestOptions.none()) @@ -149,9 +239,25 @@ interface VectorStoreServiceAsync { * the same as [VectorStoreServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve(vectorStoreId: String): CompletableFuture> = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( - params: VectorStoreRetrieveParams - ): CompletableFuture> = retrieve(params, RequestOptions.none()) + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + ): CompletableFuture> = + retrieve(vectorStoreId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -160,14 +266,44 @@ interface VectorStoreServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + params: VectorStoreRetrieveParams + ): CompletableFuture> = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /vector_stores/{vector_store_id}`, but is otherwise * the same as [VectorStoreServiceAsync.update]. */ @MustBeClosed + fun update(vectorStoreId: String): CompletableFuture> = + update(vectorStoreId, VectorStoreUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed fun update( - params: VectorStoreUpdateParams - ): CompletableFuture> = update(params, RequestOptions.none()) + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + ): CompletableFuture> = + update(vectorStoreId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -176,6 +312,20 @@ interface VectorStoreServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [update] */ + @MustBeClosed + fun update( + params: VectorStoreUpdateParams + ): CompletableFuture> = update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + update(vectorStoreId, VectorStoreUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /vector_stores`, but is otherwise the same as * [VectorStoreServiceAsync.list]. @@ -210,10 +360,25 @@ interface VectorStoreServiceAsync { * otherwise the same as [VectorStoreServiceAsync.delete]. */ @MustBeClosed + fun delete(vectorStoreId: String): CompletableFuture> = + delete(vectorStoreId, VectorStoreDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed fun delete( - params: VectorStoreDeleteParams + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - delete(params, RequestOptions.none()) + delete(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + ): CompletableFuture> = + delete(vectorStoreId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -222,11 +387,43 @@ interface VectorStoreServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [delete] */ + @MustBeClosed + fun delete( + params: VectorStoreDeleteParams + ): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(vectorStoreId, VectorStoreDeleteParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /vector_stores/{vector_store_id}/search`, but is * otherwise the same as [VectorStoreServiceAsync.search]. */ @MustBeClosed + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + ): CompletableFuture> = + search(vectorStoreId, params, RequestOptions.none()) + + /** @see [search] */ + @MustBeClosed + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + search(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [search] */ + @MustBeClosed fun search( params: VectorStoreSearchParams ): CompletableFuture> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsyncImpl.kt index da248f22b..346bb0737 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/VectorStoreServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -33,6 +34,7 @@ import com.openai.services.async.vectorstores.FileBatchServiceAsyncImpl import com.openai.services.async.vectorstores.FileServiceAsync import com.openai.services.async.vectorstores.FileServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : VectorStoreServiceAsync { @@ -155,6 +157,9 @@ class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions params: VectorStoreRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -185,6 +190,9 @@ class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions params: VectorStoreUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -239,6 +247,7 @@ class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions .let { VectorStoreListPageAsync.builder() .service(VectorStoreServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -254,6 +263,9 @@ class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions params: VectorStoreDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -286,6 +298,9 @@ class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions params: VectorStoreSearchParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -309,6 +324,7 @@ class VectorStoreServiceAsyncImpl internal constructor(private val clientOptions .let { VectorStoreSearchPageAsync.builder() .service(VectorStoreServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsync.kt index 84e33a144..b36485ed4 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsync.kt @@ -33,8 +33,22 @@ interface AssistantServiceAsync { ): CompletableFuture /** Retrieves an assistant. */ - fun retrieve(params: AssistantRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(assistantId: String): CompletableFuture = + retrieve(assistantId, AssistantRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + ): CompletableFuture = retrieve(assistantId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -42,9 +56,34 @@ interface AssistantServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: AssistantRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + assistantId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(assistantId, AssistantRetrieveParams.none(), requestOptions) + /** Modifies an assistant. */ - fun update(params: AssistantUpdateParams): CompletableFuture = - update(params, RequestOptions.none()) + fun update(assistantId: String): CompletableFuture = + update(assistantId, AssistantUpdateParams.none()) + + /** @see [update] */ + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [update] */ + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + ): CompletableFuture = update(assistantId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -52,6 +91,14 @@ interface AssistantServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [update] */ + fun update(params: AssistantUpdateParams): CompletableFuture = + update(params, RequestOptions.none()) + + /** @see [update] */ + fun update(assistantId: String, requestOptions: RequestOptions): CompletableFuture = + update(assistantId, AssistantUpdateParams.none(), requestOptions) + /** Returns a list of assistants. */ fun list(): CompletableFuture = list(AssistantListParams.none()) @@ -71,8 +118,22 @@ interface AssistantServiceAsync { list(AssistantListParams.none(), requestOptions) /** Delete an assistant. */ - fun delete(params: AssistantDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(assistantId: String): CompletableFuture = + delete(assistantId, AssistantDeleteParams.none()) + + /** @see [delete] */ + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + ): CompletableFuture = delete(assistantId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -80,6 +141,17 @@ interface AssistantServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: AssistantDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + assistantId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + delete(assistantId, AssistantDeleteParams.none(), requestOptions) + /** * A view of [AssistantServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -105,9 +177,25 @@ interface AssistantServiceAsync { * same as [AssistantServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve(assistantId: String): CompletableFuture> = + retrieve(assistantId, AssistantRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( - params: AssistantRetrieveParams - ): CompletableFuture> = retrieve(params, RequestOptions.none()) + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + ): CompletableFuture> = + retrieve(assistantId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -116,13 +204,44 @@ interface AssistantServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + params: AssistantRetrieveParams + ): CompletableFuture> = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + assistantId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(assistantId, AssistantRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /assistants/{assistant_id}`, but is otherwise the * same as [AssistantServiceAsync.update]. */ @MustBeClosed - fun update(params: AssistantUpdateParams): CompletableFuture> = - update(params, RequestOptions.none()) + fun update(assistantId: String): CompletableFuture> = + update(assistantId, AssistantUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + ): CompletableFuture> = + update(assistantId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -131,6 +250,19 @@ interface AssistantServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [update] */ + @MustBeClosed + fun update(params: AssistantUpdateParams): CompletableFuture> = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + assistantId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + update(assistantId, AssistantUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /assistants`, but is otherwise the same as * [AssistantServiceAsync.list]. @@ -165,10 +297,25 @@ interface AssistantServiceAsync { * same as [AssistantServiceAsync.delete]. */ @MustBeClosed + fun delete(assistantId: String): CompletableFuture> = + delete(assistantId, AssistantDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed fun delete( - params: AssistantDeleteParams + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - delete(params, RequestOptions.none()) + delete(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + ): CompletableFuture> = + delete(assistantId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -176,5 +323,20 @@ interface AssistantServiceAsync { params: AssistantDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [delete] */ + @MustBeClosed + fun delete( + params: AssistantDeleteParams + ): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + assistantId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(assistantId, AssistantDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsyncImpl.kt index 7eb203939..d7d746f2d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/AssistantServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.beta import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -26,6 +27,7 @@ import com.openai.models.beta.assistants.AssistantListParams import com.openai.models.beta.assistants.AssistantRetrieveParams import com.openai.models.beta.assistants.AssistantUpdateParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class AssistantServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : AssistantServiceAsync { @@ -119,6 +121,9 @@ class AssistantServiceAsyncImpl internal constructor(private val clientOptions: params: AssistantRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("assistantId", params.assistantId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -149,6 +154,9 @@ class AssistantServiceAsyncImpl internal constructor(private val clientOptions: params: AssistantUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("assistantId", params.assistantId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -207,6 +215,7 @@ class AssistantServiceAsyncImpl internal constructor(private val clientOptions: .let { AssistantListPageAsync.builder() .service(AssistantServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -222,6 +231,9 @@ class AssistantServiceAsyncImpl internal constructor(private val clientOptions: params: AssistantDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("assistantId", params.assistantId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsync.kt index 76a89f632..5eaf86429 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsync.kt @@ -49,8 +49,22 @@ interface ThreadServiceAsync { create(ThreadCreateParams.none(), requestOptions) /** Retrieves a thread. */ - fun retrieve(params: ThreadRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(threadId: String): CompletableFuture = + retrieve(threadId, ThreadRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + ): CompletableFuture = retrieve(threadId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -58,9 +72,31 @@ interface ThreadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: ThreadRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(threadId: String, requestOptions: RequestOptions): CompletableFuture = + retrieve(threadId, ThreadRetrieveParams.none(), requestOptions) + /** Modifies a thread. */ - fun update(params: ThreadUpdateParams): CompletableFuture = - update(params, RequestOptions.none()) + fun update(threadId: String): CompletableFuture = + update(threadId, ThreadUpdateParams.none()) + + /** @see [update] */ + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [update] */ + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + ): CompletableFuture = update(threadId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -68,9 +104,31 @@ interface ThreadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [update] */ + fun update(params: ThreadUpdateParams): CompletableFuture = + update(params, RequestOptions.none()) + + /** @see [update] */ + fun update(threadId: String, requestOptions: RequestOptions): CompletableFuture = + update(threadId, ThreadUpdateParams.none(), requestOptions) + /** Delete a thread. */ - fun delete(params: ThreadDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(threadId: String): CompletableFuture = + delete(threadId, ThreadDeleteParams.none()) + + /** @see [delete] */ + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + ): CompletableFuture = delete(threadId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -78,6 +136,14 @@ interface ThreadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: ThreadDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(threadId: String, requestOptions: RequestOptions): CompletableFuture = + delete(threadId, ThreadDeleteParams.none(), requestOptions) + /** Create a thread and run it in one request. */ fun createAndRun(params: ThreadCreateAndRunParams): CompletableFuture = createAndRun(params, RequestOptions.none()) @@ -139,8 +205,25 @@ interface ThreadServiceAsync { * [ThreadServiceAsync.retrieve]. */ @MustBeClosed - fun retrieve(params: ThreadRetrieveParams): CompletableFuture> = - retrieve(params, RequestOptions.none()) + fun retrieve(threadId: String): CompletableFuture> = + retrieve(threadId, ThreadRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + ): CompletableFuture> = + retrieve(threadId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -149,13 +232,43 @@ interface ThreadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ThreadRetrieveParams): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(threadId, ThreadRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /threads/{thread_id}`, but is otherwise the same as * [ThreadServiceAsync.update]. */ @MustBeClosed - fun update(params: ThreadUpdateParams): CompletableFuture> = - update(params, RequestOptions.none()) + fun update(threadId: String): CompletableFuture> = + update(threadId, ThreadUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + ): CompletableFuture> = + update(threadId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -164,13 +277,43 @@ interface ThreadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [update] */ + @MustBeClosed + fun update(params: ThreadUpdateParams): CompletableFuture> = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + update(threadId, ThreadUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /threads/{thread_id}`, but is otherwise the same * as [ThreadServiceAsync.delete]. */ @MustBeClosed - fun delete(params: ThreadDeleteParams): CompletableFuture> = - delete(params, RequestOptions.none()) + fun delete(threadId: String): CompletableFuture> = + delete(threadId, ThreadDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + ): CompletableFuture> = + delete(threadId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -179,6 +322,19 @@ interface ThreadServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [delete] */ + @MustBeClosed + fun delete(params: ThreadDeleteParams): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(threadId, ThreadDeleteParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /threads/runs`, but is otherwise the same as * [ThreadServiceAsync.createAndRun]. diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsyncImpl.kt index c8334900e..a0193523c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/ThreadServiceAsyncImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.async.beta import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.mapJson @@ -37,6 +38,7 @@ import com.openai.services.async.beta.threads.MessageServiceAsyncImpl import com.openai.services.async.beta.threads.RunServiceAsync import com.openai.services.async.beta.threads.RunServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class ThreadServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : ThreadServiceAsync { @@ -160,6 +162,9 @@ class ThreadServiceAsyncImpl internal constructor(private val clientOptions: Cli params: ThreadRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -190,6 +195,9 @@ class ThreadServiceAsyncImpl internal constructor(private val clientOptions: Cli params: ThreadUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -221,6 +229,9 @@ class ThreadServiceAsyncImpl internal constructor(private val clientOptions: Cli params: ThreadDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsync.kt index 364851ad8..4ec7a1515 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsync.kt @@ -23,6 +23,18 @@ interface MessageServiceAsync { fun withRawResponse(): WithRawResponse /** Create a message. */ + fun create(threadId: String, params: MessageCreateParams): CompletableFuture = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + threadId: String, + params: MessageCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ fun create(params: MessageCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -33,6 +45,18 @@ interface MessageServiceAsync { ): CompletableFuture /** Retrieve a message. */ + fun retrieve(messageId: String, params: MessageRetrieveParams): CompletableFuture = + retrieve(messageId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + messageId: String, + params: MessageRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: MessageRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -43,6 +67,18 @@ interface MessageServiceAsync { ): CompletableFuture /** Modifies a message. */ + fun update(messageId: String, params: MessageUpdateParams): CompletableFuture = + update(messageId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + messageId: String, + params: MessageUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [update] */ fun update(params: MessageUpdateParams): CompletableFuture = update(params, RequestOptions.none()) @@ -53,8 +89,22 @@ interface MessageServiceAsync { ): CompletableFuture /** Returns a list of messages for a given thread. */ - fun list(params: MessageListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(threadId: String): CompletableFuture = + list(threadId, MessageListParams.none()) + + /** @see [list] */ + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + ): CompletableFuture = list(threadId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -62,7 +112,30 @@ interface MessageServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: MessageListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + list(threadId, MessageListParams.none(), requestOptions) + /** Deletes a message. */ + fun delete(messageId: String, params: MessageDeleteParams): CompletableFuture = + delete(messageId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + messageId: String, + params: MessageDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: MessageDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) @@ -82,6 +155,23 @@ interface MessageServiceAsync { * the same as [MessageServiceAsync.create]. */ @MustBeClosed + fun create( + threadId: String, + params: MessageCreateParams, + ): CompletableFuture> = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + threadId: String, + params: MessageCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: MessageCreateParams): CompletableFuture> = create(params, RequestOptions.none()) @@ -97,6 +187,23 @@ interface MessageServiceAsync { * otherwise the same as [MessageServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + messageId: String, + params: MessageRetrieveParams, + ): CompletableFuture> = + retrieve(messageId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + messageId: String, + params: MessageRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: MessageRetrieveParams): CompletableFuture> = retrieve(params, RequestOptions.none()) @@ -112,6 +219,23 @@ interface MessageServiceAsync { * otherwise the same as [MessageServiceAsync.update]. */ @MustBeClosed + fun update( + messageId: String, + params: MessageUpdateParams, + ): CompletableFuture> = + update(messageId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + messageId: String, + params: MessageUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: MessageUpdateParams): CompletableFuture> = update(params, RequestOptions.none()) @@ -127,10 +251,25 @@ interface MessageServiceAsync { * same as [MessageServiceAsync.list]. */ @MustBeClosed + fun list(threadId: String): CompletableFuture> = + list(threadId, MessageListParams.none()) + + /** @see [list] */ + @MustBeClosed fun list( - params: MessageListParams + threadId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - list(params, RequestOptions.none()) + list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + ): CompletableFuture> = + list(threadId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -139,11 +278,43 @@ interface MessageServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [list] */ + @MustBeClosed + fun list( + params: MessageListParams + ): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(threadId, MessageListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /threads/{thread_id}/messages/{message_id}`, but * is otherwise the same as [MessageServiceAsync.delete]. */ @MustBeClosed + fun delete( + messageId: String, + params: MessageDeleteParams, + ): CompletableFuture> = + delete(messageId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + messageId: String, + params: MessageDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete( params: MessageDeleteParams ): CompletableFuture> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncImpl.kt index 9753c5f62..07aad9bef 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.beta.threads import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -26,6 +27,7 @@ import com.openai.models.beta.threads.messages.MessageListParams import com.openai.models.beta.threads.messages.MessageRetrieveParams import com.openai.models.beta.threads.messages.MessageUpdateParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class MessageServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : MessageServiceAsync { @@ -88,6 +90,9 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl params: MessageCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -119,6 +124,9 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl params: MessageRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -154,6 +162,9 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl params: MessageUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -191,6 +202,9 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl params: MessageListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -213,6 +227,7 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl .let { MessageListPageAsync.builder() .service(MessageServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -228,6 +243,9 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl params: MessageDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsync.kt index ca8f68ad5..660d74de5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsync.kt @@ -29,6 +29,18 @@ interface RunServiceAsync { fun steps(): StepServiceAsync /** Create a run. */ + fun create(threadId: String, params: RunCreateParams): CompletableFuture = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ fun create(params: RunCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -39,6 +51,21 @@ interface RunServiceAsync { ): CompletableFuture /** Create a run. */ + fun createStreaming( + threadId: String, + params: RunCreateParams, + ): AsyncStreamResponse = + createStreaming(threadId, params, RequestOptions.none()) + + /** @see [createStreaming] */ + fun createStreaming( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse = + createStreaming(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [createStreaming] */ fun createStreaming(params: RunCreateParams): AsyncStreamResponse = createStreaming(params, RequestOptions.none()) @@ -49,6 +76,17 @@ interface RunServiceAsync { ): AsyncStreamResponse /** Retrieves a run. */ + fun retrieve(runId: String, params: RunRetrieveParams): CompletableFuture = + retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: RunRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -59,6 +97,17 @@ interface RunServiceAsync { ): CompletableFuture /** Modifies a run. */ + fun update(runId: String, params: RunUpdateParams): CompletableFuture = + update(runId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + runId: String, + params: RunUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = update(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [update] */ fun update(params: RunUpdateParams): CompletableFuture = update(params, RequestOptions.none()) @@ -69,8 +118,22 @@ interface RunServiceAsync { ): CompletableFuture /** Returns a list of runs belonging to a thread. */ - fun list(params: RunListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(threadId: String): CompletableFuture = + list(threadId, RunListParams.none()) + + /** @see [list] */ + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + ): CompletableFuture = list(threadId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -78,7 +141,28 @@ interface RunServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: RunListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture = list(threadId, RunListParams.none(), requestOptions) + /** Cancels a run that is `in_progress`. */ + fun cancel(runId: String, params: RunCancelParams): CompletableFuture = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ fun cancel(params: RunCancelParams): CompletableFuture = cancel(params, RequestOptions.none()) @@ -93,6 +177,20 @@ interface RunServiceAsync { * `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls * once they're all completed. All outputs must be submitted in a single request. */ + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + ): CompletableFuture = submitToolOutputs(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputs] */ + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + submitToolOutputs(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputs] */ fun submitToolOutputs(params: RunSubmitToolOutputsParams): CompletableFuture = submitToolOutputs(params, RequestOptions.none()) @@ -107,6 +205,21 @@ interface RunServiceAsync { * `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls * once they're all completed. All outputs must be submitted in a single request. */ + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + ): AsyncStreamResponse = + submitToolOutputsStreaming(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputsStreaming] */ + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): AsyncStreamResponse = + submitToolOutputsStreaming(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputsStreaming] */ fun submitToolOutputsStreaming( params: RunSubmitToolOutputsParams ): AsyncStreamResponse = @@ -128,6 +241,22 @@ interface RunServiceAsync { * same as [RunServiceAsync.create]. */ @MustBeClosed + fun create( + threadId: String, + params: RunCreateParams, + ): CompletableFuture> = create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: RunCreateParams): CompletableFuture> = create(params, RequestOptions.none()) @@ -143,6 +272,23 @@ interface RunServiceAsync { * same as [RunServiceAsync.createStreaming]. */ @MustBeClosed + fun createStreaming( + threadId: String, + params: RunCreateParams, + ): CompletableFuture>> = + createStreaming(threadId, params, RequestOptions.none()) + + /** @see [createStreaming] */ + @MustBeClosed + fun createStreaming( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + createStreaming(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [createStreaming] */ + @MustBeClosed fun createStreaming( params: RunCreateParams ): CompletableFuture>> = @@ -160,6 +306,22 @@ interface RunServiceAsync { * otherwise the same as [RunServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + ): CompletableFuture> = retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: RunRetrieveParams): CompletableFuture> = retrieve(params, RequestOptions.none()) @@ -175,6 +337,22 @@ interface RunServiceAsync { * otherwise the same as [RunServiceAsync.update]. */ @MustBeClosed + fun update( + runId: String, + params: RunUpdateParams, + ): CompletableFuture> = update(runId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + runId: String, + params: RunUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: RunUpdateParams): CompletableFuture> = update(params, RequestOptions.none()) @@ -190,8 +368,25 @@ interface RunServiceAsync { * same as [RunServiceAsync.list]. */ @MustBeClosed - fun list(params: RunListParams): CompletableFuture> = - list(params, RequestOptions.none()) + fun list(threadId: String): CompletableFuture> = + list(threadId, RunListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + ): CompletableFuture> = + list(threadId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -200,11 +395,40 @@ interface RunServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [list] */ + @MustBeClosed + fun list(params: RunListParams): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(threadId, RunListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /threads/{thread_id}/runs/{run_id}/cancel`, but is * otherwise the same as [RunServiceAsync.cancel]. */ @MustBeClosed + fun cancel( + runId: String, + params: RunCancelParams, + ): CompletableFuture> = cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed fun cancel(params: RunCancelParams): CompletableFuture> = cancel(params, RequestOptions.none()) @@ -221,6 +445,23 @@ interface RunServiceAsync { * [RunServiceAsync.submitToolOutputs]. */ @MustBeClosed + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + ): CompletableFuture> = + submitToolOutputs(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputs] */ + @MustBeClosed + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + submitToolOutputs(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputs] */ + @MustBeClosed fun submitToolOutputs( params: RunSubmitToolOutputsParams ): CompletableFuture> = @@ -239,6 +480,23 @@ interface RunServiceAsync { * [RunServiceAsync.submitToolOutputsStreaming]. */ @MustBeClosed + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + ): CompletableFuture>> = + submitToolOutputsStreaming(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputsStreaming] */ + @MustBeClosed + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture>> = + submitToolOutputsStreaming(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputsStreaming] */ + @MustBeClosed fun submitToolOutputsStreaming( params: RunSubmitToolOutputsParams ): CompletableFuture>> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncImpl.kt index 9a15dc341..34ff48554 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.async.beta.threads import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.mapJson @@ -36,6 +37,7 @@ import com.openai.models.beta.threads.runs.RunUpdateParams import com.openai.services.async.beta.threads.runs.StepServiceAsync import com.openai.services.async.beta.threads.runs.StepServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class RunServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : RunServiceAsync { @@ -135,6 +137,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -172,6 +177,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunCreateParams, requestOptions: RequestOptions, ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -218,6 +226,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -248,6 +259,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -280,6 +294,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -302,6 +319,7 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client .let { RunListPageAsync.builder() .service(RunServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -317,6 +335,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunCancelParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -354,6 +375,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunSubmitToolOutputsParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -394,6 +418,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunSubmitToolOutputsParams, requestOptions: RequestOptions, ): CompletableFuture>> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsync.kt index 3718a766d..6f92544ac 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsync.kt @@ -19,6 +19,18 @@ interface StepServiceAsync { fun withRawResponse(): WithRawResponse /** Retrieves a run step. */ + fun retrieve(stepId: String, params: StepRetrieveParams): CompletableFuture = + retrieve(stepId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + stepId: String, + params: StepRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().stepId(stepId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: StepRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -29,6 +41,18 @@ interface StepServiceAsync { ): CompletableFuture /** Returns a list of run steps belonging to a run. */ + fun list(runId: String, params: StepListParams): CompletableFuture = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + fun list( + runId: String, + params: StepListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ fun list(params: StepListParams): CompletableFuture = list(params, RequestOptions.none()) @@ -46,6 +70,23 @@ interface StepServiceAsync { * but is otherwise the same as [StepServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + stepId: String, + params: StepRetrieveParams, + ): CompletableFuture> = + retrieve(stepId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + stepId: String, + params: StepRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().stepId(stepId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: StepRetrieveParams): CompletableFuture> = retrieve(params, RequestOptions.none()) @@ -61,6 +102,23 @@ interface StepServiceAsync { * otherwise the same as [StepServiceAsync.list]. */ @MustBeClosed + fun list( + runId: String, + params: StepListParams, + ): CompletableFuture> = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + runId: String, + params: StepListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed fun list(params: StepListParams): CompletableFuture> = list(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsyncImpl.kt index 9f3f8350c..49b9797b2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/beta/threads/runs/StepServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.beta.threads.runs import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -21,6 +22,7 @@ import com.openai.models.beta.threads.runs.steps.StepListPageResponse import com.openai.models.beta.threads.runs.steps.StepListParams import com.openai.models.beta.threads.runs.steps.StepRetrieveParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class StepServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : StepServiceAsync { @@ -62,6 +64,9 @@ class StepServiceAsyncImpl internal constructor(private val clientOptions: Clien params: StepRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("stepId", params.stepId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -100,6 +105,9 @@ class StepServiceAsyncImpl internal constructor(private val clientOptions: Clien params: StepListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -128,6 +136,7 @@ class StepServiceAsyncImpl internal constructor(private val clientOptions: Clien .let { StepListPageAsync.builder() .service(StepServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt index 50e7adffa..2890cb312 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsync.kt @@ -87,8 +87,22 @@ interface ChatCompletionServiceAsync { * Get a stored chat completion. Only Chat Completions that have been created with the `store` * parameter set to `true` will be returned. */ - fun retrieve(params: ChatCompletionRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(completionId: String): CompletableFuture = + retrieve(completionId, ChatCompletionRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + ): CompletableFuture = retrieve(completionId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -96,11 +110,36 @@ interface ChatCompletionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: ChatCompletionRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + completionId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(completionId, ChatCompletionRetrieveParams.none(), requestOptions) + /** * Modify a stored chat completion. Only Chat Completions that have been created with the * `store` parameter set to `true` can be modified. Currently, the only supported modification * is to update the `metadata` field. */ + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + ): CompletableFuture = update(completionId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [update] */ fun update(params: ChatCompletionUpdateParams): CompletableFuture = update(params, RequestOptions.none()) @@ -136,8 +175,23 @@ interface ChatCompletionServiceAsync { * Delete a stored chat completion. Only Chat Completions that have been created with the * `store` parameter set to `true` can be deleted. */ - fun delete(params: ChatCompletionDeleteParams): CompletableFuture = - delete(params, RequestOptions.none()) + fun delete(completionId: String): CompletableFuture = + delete(completionId, ChatCompletionDeleteParams.none()) + + /** @see [delete] */ + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + ): CompletableFuture = + delete(completionId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -145,6 +199,17 @@ interface ChatCompletionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [delete] */ + fun delete(params: ChatCompletionDeleteParams): CompletableFuture = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + completionId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + delete(completionId, ChatCompletionDeleteParams.none(), requestOptions) + /** * A view of [ChatCompletionServiceAsync] that provides access to raw HTTP responses for each * method. @@ -192,10 +257,25 @@ interface ChatCompletionServiceAsync { * the same as [ChatCompletionServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve(completionId: String): CompletableFuture> = + retrieve(completionId, ChatCompletionRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( - params: ChatCompletionRetrieveParams + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - retrieve(params, RequestOptions.none()) + retrieve(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + ): CompletableFuture> = + retrieve(completionId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -204,11 +284,43 @@ interface ChatCompletionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + params: ChatCompletionRetrieveParams + ): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + completionId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(completionId, ChatCompletionRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /chat/completions/{completion_id}`, but is * otherwise the same as [ChatCompletionServiceAsync.update]. */ @MustBeClosed + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + ): CompletableFuture> = + update(completionId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update( params: ChatCompletionUpdateParams ): CompletableFuture> = @@ -256,9 +368,26 @@ interface ChatCompletionServiceAsync { */ @MustBeClosed fun delete( - params: ChatCompletionDeleteParams + completionId: String ): CompletableFuture> = - delete(params, RequestOptions.none()) + delete(completionId, ChatCompletionDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + ): CompletableFuture> = + delete(completionId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -266,5 +395,20 @@ interface ChatCompletionServiceAsync { params: ChatCompletionDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [delete] */ + @MustBeClosed + fun delete( + params: ChatCompletionDeleteParams + ): CompletableFuture> = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + completionId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + delete(completionId, ChatCompletionDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncImpl.kt index 783a608dc..260a4619c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.async.chat import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.mapJson @@ -186,6 +187,9 @@ internal constructor(private val clientOptions: ClientOptions) : ChatCompletionS params: ChatCompletionRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -215,6 +219,9 @@ internal constructor(private val clientOptions: ClientOptions) : ChatCompletionS params: ChatCompletionUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -271,6 +278,7 @@ internal constructor(private val clientOptions: ClientOptions) : ChatCompletionS .let { ChatCompletionListPageAsync.builder() .service(ChatCompletionServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -287,6 +295,9 @@ internal constructor(private val clientOptions: ClientOptions) : ChatCompletionS params: ChatCompletionDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsync.kt index 3c5d17d36..6edcc5a02 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsync.kt @@ -20,8 +20,22 @@ interface MessageServiceAsync { * Get the messages in a stored chat completion. Only Chat Completions that have been created * with the `store` parameter set to `true` will be returned. */ - fun list(params: MessageListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(completionId: String): CompletableFuture = + list(completionId, MessageListParams.none()) + + /** @see [list] */ + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [list] */ + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + ): CompletableFuture = list(completionId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -29,6 +43,17 @@ interface MessageServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: MessageListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list( + completionId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + list(completionId, MessageListParams.none(), requestOptions) + /** * A view of [MessageServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -39,10 +64,25 @@ interface MessageServiceAsync { * otherwise the same as [MessageServiceAsync.list]. */ @MustBeClosed + fun list(completionId: String): CompletableFuture> = + list(completionId, MessageListParams.none()) + + /** @see [list] */ + @MustBeClosed fun list( - params: MessageListParams + completionId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - list(params, RequestOptions.none()) + list(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + ): CompletableFuture> = + list(completionId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -50,5 +90,20 @@ interface MessageServiceAsync { params: MessageListParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [list] */ + @MustBeClosed + fun list( + params: MessageListParams + ): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + completionId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(completionId, MessageListParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncImpl.kt index c66410b5c..271a18a6d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.chat.completions import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -18,6 +19,7 @@ import com.openai.models.chat.completions.messages.MessageListPageAsync import com.openai.models.chat.completions.messages.MessageListPageResponse import com.openai.models.chat.completions.messages.MessageListParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class MessageServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : MessageServiceAsync { @@ -48,6 +50,9 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl params: MessageListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -69,6 +74,7 @@ class MessageServiceAsyncImpl internal constructor(private val clientOptions: Cl .let { MessageListPageAsync.builder() .service(MessageServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsync.kt index 801e00e47..630a6e697 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsync.kt @@ -28,6 +28,18 @@ interface RunServiceAsync { fun outputItems(): OutputItemServiceAsync /** Create a new evaluation run. This is the endpoint that will kick off grading. */ + fun create(evalId: String, params: RunCreateParams): CompletableFuture = + create(evalId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + evalId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [create] */ fun create(params: RunCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -38,6 +50,18 @@ interface RunServiceAsync { ): CompletableFuture /** Get an evaluation run by ID. */ + fun retrieve(runId: String, params: RunRetrieveParams): CompletableFuture = + retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: RunRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -48,8 +72,22 @@ interface RunServiceAsync { ): CompletableFuture /** Get a list of runs for an evaluation. */ - fun list(params: RunListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(evalId: String): CompletableFuture = + list(evalId, RunListParams.none()) + + /** @see [list] */ + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [list] */ + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + ): CompletableFuture = list(evalId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -57,7 +95,27 @@ interface RunServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: RunListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(evalId: String, requestOptions: RequestOptions): CompletableFuture = + list(evalId, RunListParams.none(), requestOptions) + /** Delete an eval run. */ + fun delete(runId: String, params: RunDeleteParams): CompletableFuture = + delete(runId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + runId: String, + params: RunDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: RunDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) @@ -68,6 +126,18 @@ interface RunServiceAsync { ): CompletableFuture /** Cancel an ongoing evaluation run. */ + fun cancel(runId: String, params: RunCancelParams): CompletableFuture = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ fun cancel(params: RunCancelParams): CompletableFuture = cancel(params, RequestOptions.none()) @@ -87,6 +157,23 @@ interface RunServiceAsync { * as [RunServiceAsync.create]. */ @MustBeClosed + fun create( + evalId: String, + params: RunCreateParams, + ): CompletableFuture> = + create(evalId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + evalId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: RunCreateParams): CompletableFuture> = create(params, RequestOptions.none()) @@ -102,6 +189,23 @@ interface RunServiceAsync { * the same as [RunServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + ): CompletableFuture> = + retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( params: RunRetrieveParams ): CompletableFuture> = @@ -119,8 +223,25 @@ interface RunServiceAsync { * [RunServiceAsync.list]. */ @MustBeClosed - fun list(params: RunListParams): CompletableFuture> = - list(params, RequestOptions.none()) + fun list(evalId: String): CompletableFuture> = + list(evalId, RunListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + list(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + ): CompletableFuture> = + list(evalId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -129,11 +250,41 @@ interface RunServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [list] */ + @MustBeClosed + fun list(params: RunListParams): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + evalId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(evalId, RunListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /evals/{eval_id}/runs/{run_id}`, but is otherwise * the same as [RunServiceAsync.delete]. */ @MustBeClosed + fun delete( + runId: String, + params: RunDeleteParams, + ): CompletableFuture> = + delete(runId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + runId: String, + params: RunDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete(params: RunDeleteParams): CompletableFuture> = delete(params, RequestOptions.none()) @@ -149,6 +300,23 @@ interface RunServiceAsync { * the same as [RunServiceAsync.cancel]. */ @MustBeClosed + fun cancel( + runId: String, + params: RunCancelParams, + ): CompletableFuture> = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed fun cancel(params: RunCancelParams): CompletableFuture> = cancel(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsyncImpl.kt index b39590a1d..b5d6eb0e9 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/RunServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.evals import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -29,6 +30,7 @@ import com.openai.models.evals.runs.RunRetrieveResponse import com.openai.services.async.evals.runs.OutputItemServiceAsync import com.openai.services.async.evals.runs.OutputItemServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class RunServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : RunServiceAsync { @@ -98,6 +100,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -129,6 +134,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -159,6 +167,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -180,6 +191,7 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client .let { RunListPageAsync.builder() .service(RunServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -195,6 +207,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -225,6 +240,9 @@ class RunServiceAsyncImpl internal constructor(private val clientOptions: Client params: RunCancelParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsync.kt index 705932c08..6373f511b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsync.kt @@ -19,6 +19,21 @@ interface OutputItemServiceAsync { fun withRawResponse(): WithRawResponse /** Get an evaluation run output item by ID. */ + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + ): CompletableFuture = + retrieve(outputItemId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().outputItemId(outputItemId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: OutputItemRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -29,6 +44,20 @@ interface OutputItemServiceAsync { ): CompletableFuture /** Get a list of output items for an evaluation run. */ + fun list( + runId: String, + params: OutputItemListParams, + ): CompletableFuture = list(runId, params, RequestOptions.none()) + + /** @see [list] */ + fun list( + runId: String, + params: OutputItemListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ fun list(params: OutputItemListParams): CompletableFuture = list(params, RequestOptions.none()) @@ -50,6 +79,23 @@ interface OutputItemServiceAsync { * as [OutputItemServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + ): CompletableFuture> = + retrieve(outputItemId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().outputItemId(outputItemId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( params: OutputItemRetrieveParams ): CompletableFuture> = @@ -67,6 +113,23 @@ interface OutputItemServiceAsync { * otherwise the same as [OutputItemServiceAsync.list]. */ @MustBeClosed + fun list( + runId: String, + params: OutputItemListParams, + ): CompletableFuture> = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + runId: String, + params: OutputItemListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed fun list( params: OutputItemListParams ): CompletableFuture> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsyncImpl.kt index 05537bedf..ad4cd7fa2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/evals/runs/OutputItemServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.evals.runs import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -20,6 +21,7 @@ import com.openai.models.evals.runs.outputitems.OutputItemListParams import com.openai.models.evals.runs.outputitems.OutputItemRetrieveParams import com.openai.models.evals.runs.outputitems.OutputItemRetrieveResponse import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class OutputItemServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : OutputItemServiceAsync { @@ -57,6 +59,9 @@ class OutputItemServiceAsyncImpl internal constructor(private val clientOptions: params: OutputItemRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("outputItemId", params.outputItemId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -94,6 +99,9 @@ class OutputItemServiceAsyncImpl internal constructor(private val clientOptions: params: OutputItemListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -121,6 +129,7 @@ class OutputItemServiceAsyncImpl internal constructor(private val clientOptions: .let { OutputItemListPageAsync.builder() .service(OutputItemServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/AlphaServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/AlphaServiceAsync.kt new file mode 100644 index 000000000..58bc3d543 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/AlphaServiceAsync.kt @@ -0,0 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning + +import com.openai.services.async.finetuning.alpha.GraderServiceAsync + +interface AlphaServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + fun graders(): GraderServiceAsync + + /** A view of [AlphaServiceAsync] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse { + + fun graders(): GraderServiceAsync.WithRawResponse + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/AlphaServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/AlphaServiceAsyncImpl.kt new file mode 100644 index 000000000..fff90acb5 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/AlphaServiceAsyncImpl.kt @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning + +import com.openai.core.ClientOptions +import com.openai.services.async.finetuning.alpha.GraderServiceAsync +import com.openai.services.async.finetuning.alpha.GraderServiceAsyncImpl + +class AlphaServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + AlphaServiceAsync { + + private val withRawResponse: AlphaServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val graders: GraderServiceAsync by lazy { GraderServiceAsyncImpl(clientOptions) } + + override fun withRawResponse(): AlphaServiceAsync.WithRawResponse = withRawResponse + + override fun graders(): GraderServiceAsync = graders + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AlphaServiceAsync.WithRawResponse { + + private val graders: GraderServiceAsync.WithRawResponse by lazy { + GraderServiceAsyncImpl.WithRawResponseImpl(clientOptions) + } + + override fun graders(): GraderServiceAsync.WithRawResponse = graders + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsync.kt index b19633ee2..9ed467088 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsync.kt @@ -12,6 +12,8 @@ import com.openai.models.finetuning.jobs.JobListEventsPageAsync import com.openai.models.finetuning.jobs.JobListEventsParams import com.openai.models.finetuning.jobs.JobListPageAsync import com.openai.models.finetuning.jobs.JobListParams +import com.openai.models.finetuning.jobs.JobPauseParams +import com.openai.models.finetuning.jobs.JobResumeParams import com.openai.models.finetuning.jobs.JobRetrieveParams import com.openai.services.async.finetuning.jobs.CheckpointServiceAsync import java.util.concurrent.CompletableFuture @@ -48,8 +50,22 @@ interface JobServiceAsync { * * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) */ - fun retrieve(params: JobRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(fineTuningJobId: String): CompletableFuture = + retrieve(fineTuningJobId, JobRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + ): CompletableFuture = retrieve(fineTuningJobId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -57,6 +73,17 @@ interface JobServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: JobRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(fineTuningJobId, JobRetrieveParams.none(), requestOptions) + /** List your organization's fine-tuning jobs */ fun list(): CompletableFuture = list(JobListParams.none()) @@ -75,8 +102,22 @@ interface JobServiceAsync { list(JobListParams.none(), requestOptions) /** Immediately cancel a fine-tune job. */ - fun cancel(params: JobCancelParams): CompletableFuture = - cancel(params, RequestOptions.none()) + fun cancel(fineTuningJobId: String): CompletableFuture = + cancel(fineTuningJobId, JobCancelParams.none()) + + /** @see [cancel] */ + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + cancel(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [cancel] */ + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + ): CompletableFuture = cancel(fineTuningJobId, params, RequestOptions.none()) /** @see [cancel] */ fun cancel( @@ -84,9 +125,35 @@ interface JobServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [cancel] */ + fun cancel(params: JobCancelParams): CompletableFuture = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + cancel(fineTuningJobId, JobCancelParams.none(), requestOptions) + /** Get status updates for a fine-tuning job. */ - fun listEvents(params: JobListEventsParams): CompletableFuture = - listEvents(params, RequestOptions.none()) + fun listEvents(fineTuningJobId: String): CompletableFuture = + listEvents(fineTuningJobId, JobListEventsParams.none()) + + /** @see [listEvents] */ + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + listEvents(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [listEvents] */ + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + ): CompletableFuture = + listEvents(fineTuningJobId, params, RequestOptions.none()) /** @see [listEvents] */ fun listEvents( @@ -94,6 +161,87 @@ interface JobServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [listEvents] */ + fun listEvents(params: JobListEventsParams): CompletableFuture = + listEvents(params, RequestOptions.none()) + + /** @see [listEvents] */ + fun listEvents( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + listEvents(fineTuningJobId, JobListEventsParams.none(), requestOptions) + + /** Pause a fine-tune job. */ + fun pause(fineTuningJobId: String): CompletableFuture = + pause(fineTuningJobId, JobPauseParams.none()) + + /** @see [pause] */ + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + pause(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [pause] */ + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + ): CompletableFuture = pause(fineTuningJobId, params, RequestOptions.none()) + + /** @see [pause] */ + fun pause( + params: JobPauseParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [pause] */ + fun pause(params: JobPauseParams): CompletableFuture = + pause(params, RequestOptions.none()) + + /** @see [pause] */ + fun pause( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + pause(fineTuningJobId, JobPauseParams.none(), requestOptions) + + /** Resume a fine-tune job. */ + fun resume(fineTuningJobId: String): CompletableFuture = + resume(fineTuningJobId, JobResumeParams.none()) + + /** @see [resume] */ + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + resume(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [resume] */ + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + ): CompletableFuture = resume(fineTuningJobId, params, RequestOptions.none()) + + /** @see [resume] */ + fun resume( + params: JobResumeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** @see [resume] */ + fun resume(params: JobResumeParams): CompletableFuture = + resume(params, RequestOptions.none()) + + /** @see [resume] */ + fun resume( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + resume(fineTuningJobId, JobResumeParams.none(), requestOptions) + /** A view of [JobServiceAsync] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -119,8 +267,25 @@ interface JobServiceAsync { * otherwise the same as [JobServiceAsync.retrieve]. */ @MustBeClosed - fun retrieve(params: JobRetrieveParams): CompletableFuture> = - retrieve(params, RequestOptions.none()) + fun retrieve(fineTuningJobId: String): CompletableFuture> = + retrieve(fineTuningJobId, JobRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + ): CompletableFuture> = + retrieve(fineTuningJobId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -129,6 +294,19 @@ interface JobServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: JobRetrieveParams): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(fineTuningJobId, JobRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /fine_tuning/jobs`, but is otherwise the same as * [JobServiceAsync.list]. @@ -163,8 +341,25 @@ interface JobServiceAsync { * is otherwise the same as [JobServiceAsync.cancel]. */ @MustBeClosed - fun cancel(params: JobCancelParams): CompletableFuture> = - cancel(params, RequestOptions.none()) + fun cancel(fineTuningJobId: String): CompletableFuture> = + cancel(fineTuningJobId, JobCancelParams.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + cancel(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + ): CompletableFuture> = + cancel(fineTuningJobId, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -173,15 +368,45 @@ interface JobServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [cancel] */ + @MustBeClosed + fun cancel(params: JobCancelParams): CompletableFuture> = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + cancel(fineTuningJobId, JobCancelParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /fine_tuning/jobs/{fine_tuning_job_id}/events`, but * is otherwise the same as [JobServiceAsync.listEvents]. */ @MustBeClosed fun listEvents( - params: JobListEventsParams + fineTuningJobId: String ): CompletableFuture> = - listEvents(params, RequestOptions.none()) + listEvents(fineTuningJobId, JobListEventsParams.none()) + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + listEvents(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + ): CompletableFuture> = + listEvents(fineTuningJobId, params, RequestOptions.none()) /** @see [listEvents] */ @MustBeClosed @@ -189,5 +414,110 @@ interface JobServiceAsync { params: JobListEventsParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + params: JobListEventsParams + ): CompletableFuture> = + listEvents(params, RequestOptions.none()) + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + listEvents(fineTuningJobId, JobListEventsParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /fine_tuning/jobs/{fine_tuning_job_id}/pause`, but + * is otherwise the same as [JobServiceAsync.pause]. + */ + @MustBeClosed + fun pause(fineTuningJobId: String): CompletableFuture> = + pause(fineTuningJobId, JobPauseParams.none()) + + /** @see [pause] */ + @MustBeClosed + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + pause(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [pause] */ + @MustBeClosed + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + ): CompletableFuture> = + pause(fineTuningJobId, params, RequestOptions.none()) + + /** @see [pause] */ + @MustBeClosed + fun pause( + params: JobPauseParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see [pause] */ + @MustBeClosed + fun pause(params: JobPauseParams): CompletableFuture> = + pause(params, RequestOptions.none()) + + /** @see [pause] */ + @MustBeClosed + fun pause( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + pause(fineTuningJobId, JobPauseParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /fine_tuning/jobs/{fine_tuning_job_id}/resume`, but + * is otherwise the same as [JobServiceAsync.resume]. + */ + @MustBeClosed + fun resume(fineTuningJobId: String): CompletableFuture> = + resume(fineTuningJobId, JobResumeParams.none()) + + /** @see [resume] */ + @MustBeClosed + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + resume(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [resume] */ + @MustBeClosed + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + ): CompletableFuture> = + resume(fineTuningJobId, params, RequestOptions.none()) + + /** @see [resume] */ + @MustBeClosed + fun resume( + params: JobResumeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** @see [resume] */ + @MustBeClosed + fun resume(params: JobResumeParams): CompletableFuture> = + resume(params, RequestOptions.none()) + + /** @see [resume] */ + @MustBeClosed + fun resume( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + resume(fineTuningJobId, JobResumeParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsyncImpl.kt index 5ebe2d429..959d5660c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/JobServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.finetuning import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -24,10 +25,13 @@ import com.openai.models.finetuning.jobs.JobListEventsParams import com.openai.models.finetuning.jobs.JobListPageAsync import com.openai.models.finetuning.jobs.JobListPageResponse import com.openai.models.finetuning.jobs.JobListParams +import com.openai.models.finetuning.jobs.JobPauseParams +import com.openai.models.finetuning.jobs.JobResumeParams import com.openai.models.finetuning.jobs.JobRetrieveParams import com.openai.services.async.finetuning.jobs.CheckpointServiceAsync import com.openai.services.async.finetuning.jobs.CheckpointServiceAsyncImpl import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class JobServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : JobServiceAsync { @@ -79,6 +83,20 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client // get /fine_tuning/jobs/{fine_tuning_job_id}/events withRawResponse().listEvents(params, requestOptions).thenApply { it.parse() } + override fun pause( + params: JobPauseParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /fine_tuning/jobs/{fine_tuning_job_id}/pause + withRawResponse().pause(params, requestOptions).thenApply { it.parse() } + + override fun resume( + params: JobResumeParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /fine_tuning/jobs/{fine_tuning_job_id}/resume + withRawResponse().resume(params, requestOptions).thenApply { it.parse() } + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : JobServiceAsync.WithRawResponse { @@ -127,6 +145,9 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client params: JobRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -178,6 +199,7 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client .let { JobListPageAsync.builder() .service(JobServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -193,6 +215,9 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client params: JobCancelParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -224,6 +249,9 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client params: JobListEventsParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -245,6 +273,7 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client .let { JobListEventsPageAsync.builder() .service(JobServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -252,5 +281,71 @@ class JobServiceAsyncImpl internal constructor(private val clientOptions: Client } } } + + private val pauseHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + + override fun pause( + params: JobPauseParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "jobs", params._pathParam(0), "pause") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { pauseHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val resumeHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + + override fun resume( + params: JobResumeParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "jobs", params._pathParam(0), "resume") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepareAsync(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { resumeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/MethodServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/MethodServiceAsync.kt new file mode 100644 index 000000000..6c46a35d4 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/MethodServiceAsync.kt @@ -0,0 +1,16 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning + +interface MethodServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * A view of [MethodServiceAsync] that provides access to raw HTTP responses for each method. + */ + interface WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/MethodServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/MethodServiceAsyncImpl.kt new file mode 100644 index 000000000..a28030299 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/MethodServiceAsyncImpl.kt @@ -0,0 +1,18 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning + +import com.openai.core.ClientOptions + +class MethodServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + MethodServiceAsync { + + private val withRawResponse: MethodServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): MethodServiceAsync.WithRawResponse = withRawResponse + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + MethodServiceAsync.WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsync.kt new file mode 100644 index 000000000..a11d77f1d --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsync.kt @@ -0,0 +1,78 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning.alpha + +import com.google.errorprone.annotations.MustBeClosed +import com.openai.core.RequestOptions +import com.openai.core.http.HttpResponseFor +import com.openai.models.finetuning.alpha.graders.GraderRunParams +import com.openai.models.finetuning.alpha.graders.GraderRunResponse +import com.openai.models.finetuning.alpha.graders.GraderValidateParams +import com.openai.models.finetuning.alpha.graders.GraderValidateResponse +import java.util.concurrent.CompletableFuture + +interface GraderServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** Run a grader. */ + fun run(params: GraderRunParams): CompletableFuture = + run(params, RequestOptions.none()) + + /** @see [run] */ + fun run( + params: GraderRunParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** Validate a grader. */ + fun validate(params: GraderValidateParams): CompletableFuture = + validate(params, RequestOptions.none()) + + /** @see [validate] */ + fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture + + /** + * A view of [GraderServiceAsync] that provides access to raw HTTP responses for each method. + */ + interface WithRawResponse { + + /** + * Returns a raw HTTP response for `post /fine_tuning/alpha/graders/run`, but is otherwise + * the same as [GraderServiceAsync.run]. + */ + @MustBeClosed + fun run(params: GraderRunParams): CompletableFuture> = + run(params, RequestOptions.none()) + + /** @see [run] */ + @MustBeClosed + fun run( + params: GraderRunParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + + /** + * Returns a raw HTTP response for `post /fine_tuning/alpha/graders/validate`, but is + * otherwise the same as [GraderServiceAsync.validate]. + */ + @MustBeClosed + fun validate( + params: GraderValidateParams + ): CompletableFuture> = + validate(params, RequestOptions.none()) + + /** @see [validate] */ + @MustBeClosed + fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsyncImpl.kt new file mode 100644 index 000000000..9eb20ee45 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsyncImpl.kt @@ -0,0 +1,113 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning.alpha + +import com.openai.core.ClientOptions +import com.openai.core.RequestOptions +import com.openai.core.handlers.errorHandler +import com.openai.core.handlers.jsonHandler +import com.openai.core.handlers.withErrorHandler +import com.openai.core.http.HttpMethod +import com.openai.core.http.HttpRequest +import com.openai.core.http.HttpResponse.Handler +import com.openai.core.http.HttpResponseFor +import com.openai.core.http.json +import com.openai.core.http.parseable +import com.openai.core.prepareAsync +import com.openai.models.ErrorObject +import com.openai.models.finetuning.alpha.graders.GraderRunParams +import com.openai.models.finetuning.alpha.graders.GraderRunResponse +import com.openai.models.finetuning.alpha.graders.GraderValidateParams +import com.openai.models.finetuning.alpha.graders.GraderValidateResponse +import java.util.concurrent.CompletableFuture + +class GraderServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + GraderServiceAsync { + + private val withRawResponse: GraderServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): GraderServiceAsync.WithRawResponse = withRawResponse + + override fun run( + params: GraderRunParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /fine_tuning/alpha/graders/run + withRawResponse().run(params, requestOptions).thenApply { it.parse() } + + override fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions, + ): CompletableFuture = + // post /fine_tuning/alpha/graders/validate + withRawResponse().validate(params, requestOptions).thenApply { it.parse() } + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GraderServiceAsync.WithRawResponse { + + private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + + private val runHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + + override fun run( + params: GraderRunParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "alpha", "graders", "run") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { runHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + + private val validateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions, + ): CompletableFuture> { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "alpha", "graders", "validate") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepareAsync(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + return request + .thenComposeAsync { clientOptions.httpClient.executeAsync(it, requestOptions) } + .thenApply { response -> + response.parseable { + response + .use { validateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsync.kt index 6fa0d1541..0d293bcb9 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsync.kt @@ -26,6 +26,24 @@ interface PermissionServiceAsync { * This enables organization owners to share fine-tuned models with other projects in their * organization. */ + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + ): CompletableFuture = + create(fineTunedModelCheckpoint, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [create] */ fun create(params: PermissionCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -41,8 +59,26 @@ interface PermissionServiceAsync { * Organization owners can use this endpoint to view all permissions for a fine-tuned model * checkpoint. */ - fun retrieve(params: PermissionRetrieveParams): CompletableFuture = - retrieve(params, RequestOptions.none()) + fun retrieve(fineTunedModelCheckpoint: String): CompletableFuture = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [retrieve] */ + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + ): CompletableFuture = + retrieve(fineTunedModelCheckpoint, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -50,12 +86,38 @@ interface PermissionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [retrieve] */ + fun retrieve(params: PermissionRetrieveParams): CompletableFuture = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTunedModelCheckpoint: String, + requestOptions: RequestOptions, + ): CompletableFuture = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none(), requestOptions) + /** * **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). * * Organization owners can use this endpoint to delete a permission for a fine-tuned model * checkpoint. */ + fun delete( + permissionId: String, + params: PermissionDeleteParams, + ): CompletableFuture = + delete(permissionId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + permissionId: String, + params: PermissionDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().permissionId(permissionId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: PermissionDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) @@ -77,6 +139,26 @@ interface PermissionServiceAsync { * same as [PermissionServiceAsync.create]. */ @MustBeClosed + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + ): CompletableFuture> = + create(fineTunedModelCheckpoint, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [create] */ + @MustBeClosed fun create( params: PermissionCreateParams ): CompletableFuture> = @@ -96,9 +178,29 @@ interface PermissionServiceAsync { */ @MustBeClosed fun retrieve( - params: PermissionRetrieveParams + fineTunedModelCheckpoint: String ): CompletableFuture> = - retrieve(params, RequestOptions.none()) + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + ): CompletableFuture> = + retrieve(fineTunedModelCheckpoint, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -107,12 +209,44 @@ interface PermissionServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + params: PermissionRetrieveParams + ): CompletableFuture> = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTunedModelCheckpoint: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete * /fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}`, but * is otherwise the same as [PermissionServiceAsync.delete]. */ @MustBeClosed + fun delete( + permissionId: String, + params: PermissionDeleteParams, + ): CompletableFuture> = + delete(permissionId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + permissionId: String, + params: PermissionDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().permissionId(permissionId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete( params: PermissionDeleteParams ): CompletableFuture> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsyncImpl.kt index 9d763dd76..0d3bf5c02 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/checkpoints/PermissionServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.finetuning.checkpoints import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -23,6 +24,7 @@ import com.openai.models.finetuning.checkpoints.permissions.PermissionDeleteResp import com.openai.models.finetuning.checkpoints.permissions.PermissionRetrieveParams import com.openai.models.finetuning.checkpoints.permissions.PermissionRetrieveResponse import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class PermissionServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : PermissionServiceAsync { @@ -67,6 +69,9 @@ class PermissionServiceAsyncImpl internal constructor(private val clientOptions: params: PermissionCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTunedModelCheckpoint", params.fineTunedModelCheckpoint().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -94,6 +99,7 @@ class PermissionServiceAsyncImpl internal constructor(private val clientOptions: .let { PermissionCreatePageAsync.builder() .service(PermissionServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -110,6 +116,9 @@ class PermissionServiceAsyncImpl internal constructor(private val clientOptions: params: PermissionRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTunedModelCheckpoint", params.fineTunedModelCheckpoint().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -145,6 +154,9 @@ class PermissionServiceAsyncImpl internal constructor(private val clientOptions: params: PermissionDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("permissionId", params.permissionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsync.kt index a479aa81c..b53b92a99 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsync.kt @@ -17,8 +17,23 @@ interface CheckpointServiceAsync { fun withRawResponse(): WithRawResponse /** List checkpoints for a fine-tuning job. */ - fun list(params: CheckpointListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(fineTuningJobId: String): CompletableFuture = + list(fineTuningJobId, CheckpointListParams.none()) + + /** @see [list] */ + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [list] */ + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + ): CompletableFuture = + list(fineTuningJobId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -26,6 +41,17 @@ interface CheckpointServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: CheckpointListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + list(fineTuningJobId, CheckpointListParams.none(), requestOptions) + /** * A view of [CheckpointServiceAsync] that provides access to raw HTTP responses for each * method. @@ -38,9 +64,26 @@ interface CheckpointServiceAsync { */ @MustBeClosed fun list( - params: CheckpointListParams + fineTuningJobId: String ): CompletableFuture> = - list(params, RequestOptions.none()) + list(fineTuningJobId, CheckpointListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + list(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + ): CompletableFuture> = + list(fineTuningJobId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -48,5 +91,20 @@ interface CheckpointServiceAsync { params: CheckpointListParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [list] */ + @MustBeClosed + fun list( + params: CheckpointListParams + ): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(fineTuningJobId, CheckpointListParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncImpl.kt index 610145095..e4f742351 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.finetuning.jobs import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -18,6 +19,7 @@ import com.openai.models.finetuning.jobs.checkpoints.CheckpointListPageAsync import com.openai.models.finetuning.jobs.checkpoints.CheckpointListPageResponse import com.openai.models.finetuning.jobs.checkpoints.CheckpointListParams import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class CheckpointServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : CheckpointServiceAsync { @@ -48,6 +50,9 @@ class CheckpointServiceAsyncImpl internal constructor(private val clientOptions: params: CheckpointListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -69,6 +74,7 @@ class CheckpointServiceAsyncImpl internal constructor(private val clientOptions: .let { CheckpointListPageAsync.builder() .service(CheckpointServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/graders/GraderModelServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/graders/GraderModelServiceAsync.kt new file mode 100644 index 000000000..e1d626007 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/graders/GraderModelServiceAsync.kt @@ -0,0 +1,17 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.graders + +interface GraderModelServiceAsync { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * A view of [GraderModelServiceAsync] that provides access to raw HTTP responses for each + * method. + */ + interface WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/graders/GraderModelServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/graders/GraderModelServiceAsyncImpl.kt new file mode 100644 index 000000000..8132d3b8f --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/graders/GraderModelServiceAsyncImpl.kt @@ -0,0 +1,18 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.graders + +import com.openai.core.ClientOptions + +class GraderModelServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : + GraderModelServiceAsync { + + private val withRawResponse: GraderModelServiceAsync.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): GraderModelServiceAsync.WithRawResponse = withRawResponse + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GraderModelServiceAsync.WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsync.kt index c0c1abfd4..11b92dbf1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsync.kt @@ -17,8 +17,22 @@ interface InputItemServiceAsync { fun withRawResponse(): WithRawResponse /** Returns a list of input items for a given response. */ - fun list(params: InputItemListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(responseId: String): CompletableFuture = + list(responseId, InputItemListParams.none()) + + /** @see [list] */ + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [list] */ + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + ): CompletableFuture = list(responseId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -26,6 +40,17 @@ interface InputItemServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: InputItemListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list( + responseId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + list(responseId, InputItemListParams.none(), requestOptions) + /** * A view of [InputItemServiceAsync] that provides access to raw HTTP responses for each method. */ @@ -36,10 +61,25 @@ interface InputItemServiceAsync { * otherwise the same as [InputItemServiceAsync.list]. */ @MustBeClosed + fun list(responseId: String): CompletableFuture> = + list(responseId, InputItemListParams.none()) + + /** @see [list] */ + @MustBeClosed fun list( - params: InputItemListParams + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> = - list(params, RequestOptions.none()) + list(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + ): CompletableFuture> = + list(responseId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -47,5 +87,20 @@ interface InputItemServiceAsync { params: InputItemListParams, requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + + /** @see [list] */ + @MustBeClosed + fun list( + params: InputItemListParams + ): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + responseId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(responseId, InputItemListParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsyncImpl.kt index 32f8112ec..0dbd0e042 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/responses/InputItemServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.responses import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -18,6 +19,7 @@ import com.openai.models.responses.inputitems.InputItemListPageAsync import com.openai.models.responses.inputitems.InputItemListParams import com.openai.models.responses.inputitems.ResponseItemList import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class InputItemServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : InputItemServiceAsync { @@ -47,6 +49,9 @@ class InputItemServiceAsyncImpl internal constructor(private val clientOptions: params: InputItemListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("responseId", params.responseId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -68,6 +73,7 @@ class InputItemServiceAsyncImpl internal constructor(private val clientOptions: .let { InputItemListPageAsync.builder() .service(InputItemServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsync.kt index 2fd896865..7961d9b68 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsync.kt @@ -28,6 +28,18 @@ interface PartServiceAsync { * Parts when you * [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete). */ + fun create(uploadId: String, params: PartCreateParams): CompletableFuture = + create(uploadId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + uploadId: String, + params: PartCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [create] */ fun create(params: PartCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -45,6 +57,23 @@ interface PartServiceAsync { * same as [PartServiceAsync.create]. */ @MustBeClosed + fun create( + uploadId: String, + params: PartCreateParams, + ): CompletableFuture> = + create(uploadId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + uploadId: String, + params: PartCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: PartCreateParams): CompletableFuture> = create(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsyncImpl.kt index 6fddaa5a9..381fb5fb5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/uploads/PartServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.uploads import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -18,6 +19,7 @@ import com.openai.models.ErrorObject import com.openai.models.uploads.parts.PartCreateParams import com.openai.models.uploads.parts.UploadPart import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class PartServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : PartServiceAsync { @@ -47,6 +49,9 @@ class PartServiceAsyncImpl internal constructor(private val clientOptions: Clien params: PartCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("uploadId", params.uploadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsync.kt index 9eb126530..df0a4a2d4 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsync.kt @@ -21,6 +21,21 @@ interface FileBatchServiceAsync { fun withRawResponse(): WithRawResponse /** Create a vector store file batch. */ + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + ): CompletableFuture = + create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ fun create(params: FileBatchCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -31,6 +46,20 @@ interface FileBatchServiceAsync { ): CompletableFuture /** Retrieves a vector store file batch. */ + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + ): CompletableFuture = retrieve(batchId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: FileBatchRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -44,6 +73,20 @@ interface FileBatchServiceAsync { * Cancel a vector store file batch. This attempts to cancel the processing of files in this * batch as soon as possible. */ + fun cancel( + batchId: String, + params: FileBatchCancelParams, + ): CompletableFuture = cancel(batchId, params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + batchId: String, + params: FileBatchCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ fun cancel(params: FileBatchCancelParams): CompletableFuture = cancel(params, RequestOptions.none()) @@ -54,6 +97,21 @@ interface FileBatchServiceAsync { ): CompletableFuture /** Returns a list of vector store files in a batch. */ + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + ): CompletableFuture = + listFiles(batchId, params, RequestOptions.none()) + + /** @see [listFiles] */ + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + listFiles(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [listFiles] */ fun listFiles( params: FileBatchListFilesParams ): CompletableFuture = listFiles(params, RequestOptions.none()) @@ -74,6 +132,23 @@ interface FileBatchServiceAsync { * is otherwise the same as [FileBatchServiceAsync.create]. */ @MustBeClosed + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + ): CompletableFuture> = + create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create( params: FileBatchCreateParams ): CompletableFuture> = @@ -92,6 +167,23 @@ interface FileBatchServiceAsync { * [FileBatchServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + ): CompletableFuture> = + retrieve(batchId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( params: FileBatchRetrieveParams ): CompletableFuture> = @@ -110,6 +202,23 @@ interface FileBatchServiceAsync { * same as [FileBatchServiceAsync.cancel]. */ @MustBeClosed + fun cancel( + batchId: String, + params: FileBatchCancelParams, + ): CompletableFuture> = + cancel(batchId, params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + params: FileBatchCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed fun cancel( params: FileBatchCancelParams ): CompletableFuture> = @@ -128,6 +237,23 @@ interface FileBatchServiceAsync { * same as [FileBatchServiceAsync.listFiles]. */ @MustBeClosed + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + ): CompletableFuture> = + listFiles(batchId, params, RequestOptions.none()) + + /** @see [listFiles] */ + @MustBeClosed + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + listFiles(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [listFiles] */ + @MustBeClosed fun listFiles( params: FileBatchListFilesParams ): CompletableFuture> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsyncImpl.kt index e9d7625a5..1d8d80865 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileBatchServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.vectorstores import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -24,6 +25,7 @@ import com.openai.models.vectorstores.filebatches.FileBatchListFilesParams import com.openai.models.vectorstores.filebatches.FileBatchRetrieveParams import com.openai.models.vectorstores.filebatches.VectorStoreFileBatch import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class FileBatchServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : FileBatchServiceAsync { @@ -80,6 +82,9 @@ class FileBatchServiceAsyncImpl internal constructor(private val clientOptions: params: FileBatchCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -112,6 +117,9 @@ class FileBatchServiceAsyncImpl internal constructor(private val clientOptions: params: FileBatchRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -148,6 +156,9 @@ class FileBatchServiceAsyncImpl internal constructor(private val clientOptions: params: FileBatchCancelParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -186,6 +197,9 @@ class FileBatchServiceAsyncImpl internal constructor(private val clientOptions: params: FileBatchListFilesParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -214,6 +228,7 @@ class FileBatchServiceAsyncImpl internal constructor(private val clientOptions: .let { FileBatchListFilesPageAsync.builder() .service(FileBatchServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsync.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsync.kt index 27a654c38..bc0b1e49b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsync.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsync.kt @@ -29,6 +29,20 @@ interface FileServiceAsync { * [File](https://platform.openai.com/docs/api-reference/files) to a * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). */ + fun create( + vectorStoreId: String, + params: FileCreateParams, + ): CompletableFuture = create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + vectorStoreId: String, + params: FileCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ fun create(params: FileCreateParams): CompletableFuture = create(params, RequestOptions.none()) @@ -39,6 +53,18 @@ interface FileServiceAsync { ): CompletableFuture /** Retrieves a vector store file. */ + fun retrieve(fileId: String, params: FileRetrieveParams): CompletableFuture = + retrieve(fileId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + fileId: String, + params: FileRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: FileRetrieveParams): CompletableFuture = retrieve(params, RequestOptions.none()) @@ -49,6 +75,18 @@ interface FileServiceAsync { ): CompletableFuture /** Update attributes on a vector store file. */ + fun update(fileId: String, params: FileUpdateParams): CompletableFuture = + update(fileId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + fileId: String, + params: FileUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + update(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [update] */ fun update(params: FileUpdateParams): CompletableFuture = update(params, RequestOptions.none()) @@ -59,8 +97,22 @@ interface FileServiceAsync { ): CompletableFuture /** Returns a list of vector store files. */ - fun list(params: FileListParams): CompletableFuture = - list(params, RequestOptions.none()) + fun list(vectorStoreId: String): CompletableFuture = + list(vectorStoreId, FileListParams.none()) + + /** @see [list] */ + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + list(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [list] */ + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + ): CompletableFuture = list(vectorStoreId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -68,11 +120,36 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture + /** @see [list] */ + fun list(params: FileListParams): CompletableFuture = + list(params, RequestOptions.none()) + + /** @see [list] */ + fun list( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture = + list(vectorStoreId, FileListParams.none(), requestOptions) + /** * Delete a vector store file. This will remove the file from the vector store but the file * itself will not be deleted. To delete the file, use the * [delete file](https://platform.openai.com/docs/api-reference/files/delete) endpoint. */ + fun delete( + fileId: String, + params: FileDeleteParams, + ): CompletableFuture = delete(fileId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + fileId: String, + params: FileDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: FileDeleteParams): CompletableFuture = delete(params, RequestOptions.none()) @@ -83,6 +160,20 @@ interface FileServiceAsync { ): CompletableFuture /** Retrieve the parsed contents of a vector store file. */ + fun content( + fileId: String, + params: FileContentParams, + ): CompletableFuture = content(fileId, params, RequestOptions.none()) + + /** @see [content] */ + fun content( + fileId: String, + params: FileContentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture = + content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ fun content(params: FileContentParams): CompletableFuture = content(params, RequestOptions.none()) @@ -100,6 +191,23 @@ interface FileServiceAsync { * otherwise the same as [FileServiceAsync.create]. */ @MustBeClosed + fun create( + vectorStoreId: String, + params: FileCreateParams, + ): CompletableFuture> = + create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + vectorStoreId: String, + params: FileCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: FileCreateParams): CompletableFuture> = create(params, RequestOptions.none()) @@ -115,6 +223,23 @@ interface FileServiceAsync { * but is otherwise the same as [FileServiceAsync.retrieve]. */ @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams, + ): CompletableFuture> = + retrieve(fileId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( params: FileRetrieveParams ): CompletableFuture> = @@ -132,6 +257,23 @@ interface FileServiceAsync { * but is otherwise the same as [FileServiceAsync.update]. */ @MustBeClosed + fun update( + fileId: String, + params: FileUpdateParams, + ): CompletableFuture> = + update(fileId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + fileId: String, + params: FileUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + update(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: FileUpdateParams): CompletableFuture> = update(params, RequestOptions.none()) @@ -147,8 +289,25 @@ interface FileServiceAsync { * otherwise the same as [FileServiceAsync.list]. */ @MustBeClosed - fun list(params: FileListParams): CompletableFuture> = - list(params, RequestOptions.none()) + fun list(vectorStoreId: String): CompletableFuture> = + list(vectorStoreId, FileListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + list(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + ): CompletableFuture> = + list(vectorStoreId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -157,12 +316,42 @@ interface FileServiceAsync { requestOptions: RequestOptions = RequestOptions.none(), ): CompletableFuture> + /** @see [list] */ + @MustBeClosed + fun list(params: FileListParams): CompletableFuture> = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + vectorStoreId: String, + requestOptions: RequestOptions, + ): CompletableFuture> = + list(vectorStoreId, FileListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete * /vector_stores/{vector_store_id}/files/{file_id}`, but is otherwise the same as * [FileServiceAsync.delete]. */ @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams, + ): CompletableFuture> = + delete(fileId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete( params: FileDeleteParams ): CompletableFuture> = @@ -181,6 +370,23 @@ interface FileServiceAsync { * [FileServiceAsync.content]. */ @MustBeClosed + fun content( + fileId: String, + params: FileContentParams, + ): CompletableFuture> = + content(fileId, params, RequestOptions.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): CompletableFuture> = + content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ + @MustBeClosed fun content( params: FileContentParams ): CompletableFuture> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncImpl.kt index a03202c6d..9780e9b6e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.async.vectorstores import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -29,6 +30,7 @@ import com.openai.models.vectorstores.files.FileUpdateParams import com.openai.models.vectorstores.files.VectorStoreFile import com.openai.models.vectorstores.files.VectorStoreFileDeleted import java.util.concurrent.CompletableFuture +import kotlin.jvm.optionals.getOrNull class FileServiceAsyncImpl internal constructor(private val clientOptions: ClientOptions) : FileServiceAsync { @@ -98,6 +100,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileCreateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -129,6 +134,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileRetrieveParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -164,6 +172,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileUpdateParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -201,6 +212,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileListParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -223,6 +237,7 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien .let { FileListPageAsync.builder() .service(FileServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() @@ -239,6 +254,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileDeleteParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -276,6 +294,9 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien params: FileContentParams, requestOptions: RequestOptions, ): CompletableFuture> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -304,6 +325,7 @@ class FileServiceAsyncImpl internal constructor(private val clientOptions: Clien .let { FileContentPageAsync.builder() .service(FileServiceAsyncImpl(clientOptions)) + .streamHandlerExecutor(clientOptions.streamHandlerExecutor) .params(params) .response(it) .build() diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchService.kt index 6c66bb582..778efa587 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchService.kt @@ -29,7 +29,18 @@ interface BatchService { ): Batch /** Retrieves a batch. */ - fun retrieve(params: BatchRetrieveParams): Batch = retrieve(params, RequestOptions.none()) + fun retrieve(batchId: String): Batch = retrieve(batchId, BatchRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Batch = retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve(batchId: String, params: BatchRetrieveParams = BatchRetrieveParams.none()): Batch = + retrieve(batchId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -37,6 +48,13 @@ interface BatchService { requestOptions: RequestOptions = RequestOptions.none(), ): Batch + /** @see [retrieve] */ + fun retrieve(params: BatchRetrieveParams): Batch = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(batchId: String, requestOptions: RequestOptions): Batch = + retrieve(batchId, BatchRetrieveParams.none(), requestOptions) + /** List your organization's batches. */ fun list(): BatchListPage = list(BatchListParams.none()) @@ -59,7 +77,18 @@ interface BatchService { * before changing to `cancelled`, where it will have partial results (if any) available in the * output file. */ - fun cancel(params: BatchCancelParams): Batch = cancel(params, RequestOptions.none()) + fun cancel(batchId: String): Batch = cancel(batchId, BatchCancelParams.none()) + + /** @see [cancel] */ + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Batch = cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ + fun cancel(batchId: String, params: BatchCancelParams = BatchCancelParams.none()): Batch = + cancel(batchId, params, RequestOptions.none()) /** @see [cancel] */ fun cancel( @@ -67,6 +96,13 @@ interface BatchService { requestOptions: RequestOptions = RequestOptions.none(), ): Batch + /** @see [cancel] */ + fun cancel(params: BatchCancelParams): Batch = cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel(batchId: String, requestOptions: RequestOptions): Batch = + cancel(batchId, BatchCancelParams.none(), requestOptions) + /** A view of [BatchService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -90,8 +126,24 @@ interface BatchService { * [BatchService.retrieve]. */ @MustBeClosed - fun retrieve(params: BatchRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(batchId: String): HttpResponseFor = + retrieve(batchId, BatchRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + params: BatchRetrieveParams = BatchRetrieveParams.none(), + ): HttpResponseFor = retrieve(batchId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -100,6 +152,16 @@ interface BatchService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: BatchRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(batchId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(batchId, BatchRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /batches`, but is otherwise the same as * [BatchService.list]. @@ -128,8 +190,24 @@ interface BatchService { * same as [BatchService.cancel]. */ @MustBeClosed - fun cancel(params: BatchCancelParams): HttpResponseFor = - cancel(params, RequestOptions.none()) + fun cancel(batchId: String): HttpResponseFor = + cancel(batchId, BatchCancelParams.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + params: BatchCancelParams = BatchCancelParams.none(), + ): HttpResponseFor = cancel(batchId, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -137,5 +215,15 @@ interface BatchService { params: BatchCancelParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [cancel] */ + @MustBeClosed + fun cancel(params: BatchCancelParams): HttpResponseFor = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel(batchId: String, requestOptions: RequestOptions): HttpResponseFor = + cancel(batchId, BatchCancelParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchServiceImpl.kt index 7a1a929cf..51717e40d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/BatchServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -22,6 +23,7 @@ import com.openai.models.batches.BatchListPage import com.openai.models.batches.BatchListPageResponse import com.openai.models.batches.BatchListParams import com.openai.models.batches.BatchRetrieveParams +import kotlin.jvm.optionals.getOrNull class BatchServiceImpl internal constructor(private val clientOptions: ClientOptions) : BatchService { @@ -87,6 +89,9 @@ class BatchServiceImpl internal constructor(private val clientOptions: ClientOpt params: BatchRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -147,6 +152,9 @@ class BatchServiceImpl internal constructor(private val clientOptions: ClientOpt params: BatchCancelParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalService.kt index 594a1ffc9..f1af3c4cb 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalService.kt @@ -42,8 +42,20 @@ interface EvalService { ): EvalCreateResponse /** Get an evaluation by ID. */ - fun retrieve(params: EvalRetrieveParams): EvalRetrieveResponse = - retrieve(params, RequestOptions.none()) + fun retrieve(evalId: String): EvalRetrieveResponse = retrieve(evalId, EvalRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EvalRetrieveResponse = retrieve(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + ): EvalRetrieveResponse = retrieve(evalId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -51,8 +63,29 @@ interface EvalService { requestOptions: RequestOptions = RequestOptions.none(), ): EvalRetrieveResponse + /** @see [retrieve] */ + fun retrieve(params: EvalRetrieveParams): EvalRetrieveResponse = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(evalId: String, requestOptions: RequestOptions): EvalRetrieveResponse = + retrieve(evalId, EvalRetrieveParams.none(), requestOptions) + /** Update certain properties of an evaluation. */ - fun update(params: EvalUpdateParams): EvalUpdateResponse = update(params, RequestOptions.none()) + fun update(evalId: String): EvalUpdateResponse = update(evalId, EvalUpdateParams.none()) + + /** @see [update] */ + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EvalUpdateResponse = update(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [update] */ + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + ): EvalUpdateResponse = update(evalId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -60,6 +93,13 @@ interface EvalService { requestOptions: RequestOptions = RequestOptions.none(), ): EvalUpdateResponse + /** @see [update] */ + fun update(params: EvalUpdateParams): EvalUpdateResponse = update(params, RequestOptions.none()) + + /** @see [update] */ + fun update(evalId: String, requestOptions: RequestOptions): EvalUpdateResponse = + update(evalId, EvalUpdateParams.none(), requestOptions) + /** List evaluations for a project. */ fun list(): EvalListPage = list(EvalListParams.none()) @@ -78,7 +118,20 @@ interface EvalService { list(EvalListParams.none(), requestOptions) /** Delete an evaluation. */ - fun delete(params: EvalDeleteParams): EvalDeleteResponse = delete(params, RequestOptions.none()) + fun delete(evalId: String): EvalDeleteResponse = delete(evalId, EvalDeleteParams.none()) + + /** @see [delete] */ + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): EvalDeleteResponse = delete(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + ): EvalDeleteResponse = delete(evalId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -86,6 +139,13 @@ interface EvalService { requestOptions: RequestOptions = RequestOptions.none(), ): EvalDeleteResponse + /** @see [delete] */ + fun delete(params: EvalDeleteParams): EvalDeleteResponse = delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(evalId: String, requestOptions: RequestOptions): EvalDeleteResponse = + delete(evalId, EvalDeleteParams.none(), requestOptions) + /** A view of [EvalService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -111,8 +171,24 @@ interface EvalService { * [EvalService.retrieve]. */ @MustBeClosed - fun retrieve(params: EvalRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(evalId: String): HttpResponseFor = + retrieve(evalId, EvalRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + evalId: String, + params: EvalRetrieveParams = EvalRetrieveParams.none(), + ): HttpResponseFor = retrieve(evalId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -121,13 +197,42 @@ interface EvalService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: EvalRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + evalId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(evalId, EvalRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /evals/{eval_id}`, but is otherwise the same as * [EvalService.update]. */ @MustBeClosed - fun update(params: EvalUpdateParams): HttpResponseFor = - update(params, RequestOptions.none()) + fun update(evalId: String): HttpResponseFor = + update(evalId, EvalUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + evalId: String, + params: EvalUpdateParams = EvalUpdateParams.none(), + ): HttpResponseFor = update(evalId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -136,6 +241,19 @@ interface EvalService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [update] */ + @MustBeClosed + fun update(params: EvalUpdateParams): HttpResponseFor = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + evalId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(evalId, EvalUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /evals`, but is otherwise the same as * [EvalService.list]. @@ -164,8 +282,24 @@ interface EvalService { * [EvalService.delete]. */ @MustBeClosed - fun delete(params: EvalDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(evalId: String): HttpResponseFor = + delete(evalId, EvalDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + evalId: String, + params: EvalDeleteParams = EvalDeleteParams.none(), + ): HttpResponseFor = delete(evalId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -173,5 +307,18 @@ interface EvalService { params: EvalDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [delete] */ + @MustBeClosed + fun delete(params: EvalDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + evalId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(evalId, EvalDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalServiceImpl.kt index faa4cc5fd..9fda99b9c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/EvalServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -28,6 +29,7 @@ import com.openai.models.evals.EvalUpdateParams import com.openai.models.evals.EvalUpdateResponse import com.openai.services.blocking.evals.RunService import com.openai.services.blocking.evals.RunServiceImpl +import kotlin.jvm.optionals.getOrNull class EvalServiceImpl internal constructor(private val clientOptions: ClientOptions) : EvalService { @@ -119,6 +121,9 @@ class EvalServiceImpl internal constructor(private val clientOptions: ClientOpti params: EvalRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -145,6 +150,9 @@ class EvalServiceImpl internal constructor(private val clientOptions: ClientOpti params: EvalUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -206,6 +214,9 @@ class EvalServiceImpl internal constructor(private val clientOptions: ClientOpti params: EvalDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileService.kt index c952d6afa..3f4934c38 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileService.kt @@ -50,7 +50,20 @@ interface FileService { ): FileObject /** Returns information about a specific file. */ - fun retrieve(params: FileRetrieveParams): FileObject = retrieve(params, RequestOptions.none()) + fun retrieve(fileId: String): FileObject = retrieve(fileId, FileRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FileObject = retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + ): FileObject = retrieve(fileId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -58,6 +71,13 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): FileObject + /** @see [retrieve] */ + fun retrieve(params: FileRetrieveParams): FileObject = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(fileId: String, requestOptions: RequestOptions): FileObject = + retrieve(fileId, FileRetrieveParams.none(), requestOptions) + /** Returns a list of files. */ fun list(): FileListPage = list(FileListParams.none()) @@ -76,7 +96,18 @@ interface FileService { list(FileListParams.none(), requestOptions) /** Delete a file. */ - fun delete(params: FileDeleteParams): FileDeleted = delete(params, RequestOptions.none()) + fun delete(fileId: String): FileDeleted = delete(fileId, FileDeleteParams.none()) + + /** @see [delete] */ + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FileDeleted = delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ + fun delete(fileId: String, params: FileDeleteParams = FileDeleteParams.none()): FileDeleted = + delete(fileId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -84,9 +115,31 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): FileDeleted + /** @see [delete] */ + fun delete(params: FileDeleteParams): FileDeleted = delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(fileId: String, requestOptions: RequestOptions): FileDeleted = + delete(fileId, FileDeleteParams.none(), requestOptions) + /** Returns the contents of the specified file. */ @MustBeClosed - fun content(params: FileContentParams): HttpResponse = content(params, RequestOptions.none()) + fun content(fileId: String): HttpResponse = content(fileId, FileContentParams.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse = content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + ): HttpResponse = content(fileId, params, RequestOptions.none()) /** @see [content] */ @MustBeClosed @@ -95,6 +148,15 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponse + /** @see [content] */ + @MustBeClosed + fun content(params: FileContentParams): HttpResponse = content(params, RequestOptions.none()) + + /** @see [content] */ + @MustBeClosed + fun content(fileId: String, requestOptions: RequestOptions): HttpResponse = + content(fileId, FileContentParams.none(), requestOptions) + /** A view of [FileService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -118,8 +180,24 @@ interface FileService { * [FileService.retrieve]. */ @MustBeClosed - fun retrieve(params: FileRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(fileId: String): HttpResponseFor = + retrieve(fileId, FileRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams = FileRetrieveParams.none(), + ): HttpResponseFor = retrieve(fileId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -128,6 +206,16 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: FileRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(fileId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(fileId, FileRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /files`, but is otherwise the same as * [FileService.list]. @@ -156,8 +244,24 @@ interface FileService { * [FileService.delete]. */ @MustBeClosed - fun delete(params: FileDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(fileId: String): HttpResponseFor = + delete(fileId, FileDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams = FileDeleteParams.none(), + ): HttpResponseFor = delete(fileId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -166,13 +270,37 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [delete] */ + @MustBeClosed + fun delete(params: FileDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete(fileId: String, requestOptions: RequestOptions): HttpResponseFor = + delete(fileId, FileDeleteParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /files/{file_id}/content`, but is otherwise the same * as [FileService.content]. */ @MustBeClosed - fun content(params: FileContentParams): HttpResponse = - content(params, RequestOptions.none()) + fun content(fileId: String): HttpResponse = content(fileId, FileContentParams.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse = content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams = FileContentParams.none(), + ): HttpResponse = content(fileId, params, RequestOptions.none()) /** @see [content] */ @MustBeClosed @@ -180,5 +308,15 @@ interface FileService { params: FileContentParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponse + + /** @see [content] */ + @MustBeClosed + fun content(params: FileContentParams): HttpResponse = + content(params, RequestOptions.none()) + + /** @see [content] */ + @MustBeClosed + fun content(fileId: String, requestOptions: RequestOptions): HttpResponse = + content(fileId, FileContentParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileServiceImpl.kt index c9b1f1f78..0f9970290 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FileServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -26,6 +27,7 @@ import com.openai.models.files.FileListPageResponse import com.openai.models.files.FileListParams import com.openai.models.files.FileObject import com.openai.models.files.FileRetrieveParams +import kotlin.jvm.optionals.getOrNull class FileServiceImpl internal constructor(private val clientOptions: ClientOptions) : FileService { @@ -94,6 +96,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -154,6 +159,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -178,6 +186,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileContentParams, requestOptions: RequestOptions, ): HttpResponse { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningService.kt index b63806554..77f45a35d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningService.kt @@ -2,8 +2,10 @@ package com.openai.services.blocking +import com.openai.services.blocking.finetuning.AlphaService import com.openai.services.blocking.finetuning.CheckpointService import com.openai.services.blocking.finetuning.JobService +import com.openai.services.blocking.finetuning.MethodService interface FineTuningService { @@ -12,15 +14,23 @@ interface FineTuningService { */ fun withRawResponse(): WithRawResponse + fun methods(): MethodService + fun jobs(): JobService fun checkpoints(): CheckpointService + fun alpha(): AlphaService + /** A view of [FineTuningService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { + fun methods(): MethodService.WithRawResponse + fun jobs(): JobService.WithRawResponse fun checkpoints(): CheckpointService.WithRawResponse + + fun alpha(): AlphaService.WithRawResponse } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningServiceImpl.kt index afe68acc7..0f8b31d30 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/FineTuningServiceImpl.kt @@ -3,10 +3,14 @@ package com.openai.services.blocking import com.openai.core.ClientOptions +import com.openai.services.blocking.finetuning.AlphaService +import com.openai.services.blocking.finetuning.AlphaServiceImpl import com.openai.services.blocking.finetuning.CheckpointService import com.openai.services.blocking.finetuning.CheckpointServiceImpl import com.openai.services.blocking.finetuning.JobService import com.openai.services.blocking.finetuning.JobServiceImpl +import com.openai.services.blocking.finetuning.MethodService +import com.openai.services.blocking.finetuning.MethodServiceImpl class FineTuningServiceImpl internal constructor(private val clientOptions: ClientOptions) : FineTuningService { @@ -15,19 +19,31 @@ class FineTuningServiceImpl internal constructor(private val clientOptions: Clie WithRawResponseImpl(clientOptions) } + private val methods: MethodService by lazy { MethodServiceImpl(clientOptions) } + private val jobs: JobService by lazy { JobServiceImpl(clientOptions) } private val checkpoints: CheckpointService by lazy { CheckpointServiceImpl(clientOptions) } + private val alpha: AlphaService by lazy { AlphaServiceImpl(clientOptions) } + override fun withRawResponse(): FineTuningService.WithRawResponse = withRawResponse + override fun methods(): MethodService = methods + override fun jobs(): JobService = jobs override fun checkpoints(): CheckpointService = checkpoints + override fun alpha(): AlphaService = alpha + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : FineTuningService.WithRawResponse { + private val methods: MethodService.WithRawResponse by lazy { + MethodServiceImpl.WithRawResponseImpl(clientOptions) + } + private val jobs: JobService.WithRawResponse by lazy { JobServiceImpl.WithRawResponseImpl(clientOptions) } @@ -36,8 +52,16 @@ class FineTuningServiceImpl internal constructor(private val clientOptions: Clie CheckpointServiceImpl.WithRawResponseImpl(clientOptions) } + private val alpha: AlphaService.WithRawResponse by lazy { + AlphaServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun methods(): MethodService.WithRawResponse = methods + override fun jobs(): JobService.WithRawResponse = jobs override fun checkpoints(): CheckpointService.WithRawResponse = checkpoints + + override fun alpha(): AlphaService.WithRawResponse = alpha } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/GraderService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/GraderService.kt new file mode 100644 index 000000000..2c9433a24 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/GraderService.kt @@ -0,0 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking + +import com.openai.services.blocking.graders.GraderModelService + +interface GraderService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + fun graderModels(): GraderModelService + + /** A view of [GraderService] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse { + + fun graderModels(): GraderModelService.WithRawResponse + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/GraderServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/GraderServiceImpl.kt new file mode 100644 index 000000000..d6d743053 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/GraderServiceImpl.kt @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking + +import com.openai.core.ClientOptions +import com.openai.services.blocking.graders.GraderModelService +import com.openai.services.blocking.graders.GraderModelServiceImpl + +class GraderServiceImpl internal constructor(private val clientOptions: ClientOptions) : + GraderService { + + private val withRawResponse: GraderService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val graderModels: GraderModelService by lazy { GraderModelServiceImpl(clientOptions) } + + override fun withRawResponse(): GraderService.WithRawResponse = withRawResponse + + override fun graderModels(): GraderModelService = graderModels + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GraderService.WithRawResponse { + + private val graderModels: GraderModelService.WithRawResponse by lazy { + GraderModelServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun graderModels(): GraderModelService.WithRawResponse = graderModels + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelService.kt index 7b34885ad..d6550622d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelService.kt @@ -23,7 +23,18 @@ interface ModelService { * Retrieves a model instance, providing basic information about the model such as the owner and * permissioning. */ - fun retrieve(params: ModelRetrieveParams): Model = retrieve(params, RequestOptions.none()) + fun retrieve(model: String): Model = retrieve(model, ModelRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Model = retrieve(params.toBuilder().model(model).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve(model: String, params: ModelRetrieveParams = ModelRetrieveParams.none()): Model = + retrieve(model, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -31,6 +42,13 @@ interface ModelService { requestOptions: RequestOptions = RequestOptions.none(), ): Model + /** @see [retrieve] */ + fun retrieve(params: ModelRetrieveParams): Model = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(model: String, requestOptions: RequestOptions): Model = + retrieve(model, ModelRetrieveParams.none(), requestOptions) + /** * Lists the currently available models, and provides basic information about each one such as * the owner and availability. @@ -55,7 +73,18 @@ interface ModelService { * Delete a fine-tuned model. You must have the Owner role in your organization to delete a * model. */ - fun delete(params: ModelDeleteParams): ModelDeleted = delete(params, RequestOptions.none()) + fun delete(model: String): ModelDeleted = delete(model, ModelDeleteParams.none()) + + /** @see [delete] */ + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ModelDeleted = delete(params.toBuilder().model(model).build(), requestOptions) + + /** @see [delete] */ + fun delete(model: String, params: ModelDeleteParams = ModelDeleteParams.none()): ModelDeleted = + delete(model, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -63,6 +92,13 @@ interface ModelService { requestOptions: RequestOptions = RequestOptions.none(), ): ModelDeleted + /** @see [delete] */ + fun delete(params: ModelDeleteParams): ModelDeleted = delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(model: String, requestOptions: RequestOptions): ModelDeleted = + delete(model, ModelDeleteParams.none(), requestOptions) + /** A view of [ModelService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -71,8 +107,24 @@ interface ModelService { * [ModelService.retrieve]. */ @MustBeClosed - fun retrieve(params: ModelRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(model: String): HttpResponseFor = + retrieve(model, ModelRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().model(model).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + model: String, + params: ModelRetrieveParams = ModelRetrieveParams.none(), + ): HttpResponseFor = retrieve(model, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -81,6 +133,16 @@ interface ModelService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ModelRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(model: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(model, ModelRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /models`, but is otherwise the same as * [ModelService.list]. @@ -109,8 +171,24 @@ interface ModelService { * [ModelService.delete]. */ @MustBeClosed - fun delete(params: ModelDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(model: String): HttpResponseFor = + delete(model, ModelDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().model(model).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + model: String, + params: ModelDeleteParams = ModelDeleteParams.none(), + ): HttpResponseFor = delete(model, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -118,5 +196,15 @@ interface ModelService { params: ModelDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [delete] */ + @MustBeClosed + fun delete(params: ModelDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete(model: String, requestOptions: RequestOptions): HttpResponseFor = + delete(model, ModelDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelServiceImpl.kt index 6e7a023ea..7104c2edb 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ModelServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -22,6 +23,7 @@ import com.openai.models.models.ModelListPage import com.openai.models.models.ModelListPageResponse import com.openai.models.models.ModelListParams import com.openai.models.models.ModelRetrieveParams +import kotlin.jvm.optionals.getOrNull class ModelServiceImpl internal constructor(private val clientOptions: ClientOptions) : ModelService { @@ -56,12 +58,15 @@ class ModelServiceImpl internal constructor(private val clientOptions: ClientOpt params: ModelRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("model", params.model().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) .addPathSegments("models", params._pathParam(0)) .build() - .prepare(clientOptions, params, params.model()) + .prepare(clientOptions, params, params.model().get()) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) return response.parseable { @@ -116,13 +121,16 @@ class ModelServiceImpl internal constructor(private val clientOptions: ClientOpt params: ModelDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("model", params.model().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) .addPathSegments("models", params._pathParam(0)) .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } .build() - .prepare(clientOptions, params, params.model()) + .prepare(clientOptions, params, params.model().get()) val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) val response = clientOptions.httpClient.execute(request, requestOptions) return response.parseable { diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt index acced25c9..12ed80ddd 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseService.kt @@ -12,6 +12,8 @@ import com.openai.models.responses.ResponseCreateParams import com.openai.models.responses.ResponseDeleteParams import com.openai.models.responses.ResponseRetrieveParams import com.openai.models.responses.ResponseStreamEvent +import com.openai.models.responses.StructuredResponse +import com.openai.models.responses.StructuredResponseCreateParams import com.openai.services.blocking.responses.InputItemService interface ResponseService { @@ -42,6 +44,27 @@ interface ResponseService { requestOptions: RequestOptions = RequestOptions.none(), ): Response + /** + * Creates a model response. The model's structured output in JSON form will be deserialized + * automatically into an instance of the class `T`. See the SDK documentation for more details. + * + * @see create + */ + fun create(params: StructuredResponseCreateParams): StructuredResponse = + create(params, RequestOptions.none()) + + /** + * Creates a model response. The model's structured output in JSON form will be deserialized + * automatically into an instance of the class `T`. See the SDK documentation for more details. + * + * @see create + */ + fun create( + params: StructuredResponseCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StructuredResponse = + StructuredResponse(params.responseType, create(params.rawParams, requestOptions)) + /** * Creates a model response. Provide [text](https://platform.openai.com/docs/guides/text) or * [image](https://platform.openai.com/docs/guides/images) inputs to generate @@ -65,7 +88,20 @@ interface ResponseService { ): StreamResponse /** Retrieves a model response with the given ID. */ - fun retrieve(params: ResponseRetrieveParams): Response = retrieve(params, RequestOptions.none()) + fun retrieve(responseId: String): Response = retrieve(responseId, ResponseRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Response = retrieve(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + ): Response = retrieve(responseId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -73,12 +109,37 @@ interface ResponseService { requestOptions: RequestOptions = RequestOptions.none(), ): Response + /** @see [retrieve] */ + fun retrieve(params: ResponseRetrieveParams): Response = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(responseId: String, requestOptions: RequestOptions): Response = + retrieve(responseId, ResponseRetrieveParams.none(), requestOptions) + /** Deletes a model response with the given ID. */ - fun delete(params: ResponseDeleteParams) = delete(params, RequestOptions.none()) + fun delete(responseId: String) = delete(responseId, ResponseDeleteParams.none()) + + /** @see [delete] */ + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ) = delete(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [delete] */ + fun delete(responseId: String, params: ResponseDeleteParams = ResponseDeleteParams.none()) = + delete(responseId, params, RequestOptions.none()) /** @see [delete] */ fun delete(params: ResponseDeleteParams, requestOptions: RequestOptions = RequestOptions.none()) + /** @see [delete] */ + fun delete(params: ResponseDeleteParams) = delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(responseId: String, requestOptions: RequestOptions) = + delete(responseId, ResponseDeleteParams.none(), requestOptions) + /** A view of [ResponseService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -121,8 +182,24 @@ interface ResponseService { * as [ResponseService.retrieve]. */ @MustBeClosed - fun retrieve(params: ResponseRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(responseId: String): HttpResponseFor = + retrieve(responseId, ResponseRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + responseId: String, + params: ResponseRetrieveParams = ResponseRetrieveParams.none(), + ): HttpResponseFor = retrieve(responseId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -131,13 +208,41 @@ interface ResponseService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ResponseRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + responseId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(responseId, ResponseRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /responses/{response_id}`, but is otherwise the * same as [ResponseService.delete]. */ @MustBeClosed - fun delete(params: ResponseDeleteParams): HttpResponse = - delete(params, RequestOptions.none()) + fun delete(responseId: String): HttpResponse = + delete(responseId, ResponseDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponse = delete(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + responseId: String, + params: ResponseDeleteParams = ResponseDeleteParams.none(), + ): HttpResponse = delete(responseId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -145,5 +250,15 @@ interface ResponseService { params: ResponseDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponse + + /** @see [delete] */ + @MustBeClosed + fun delete(params: ResponseDeleteParams): HttpResponse = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete(responseId: String, requestOptions: RequestOptions): HttpResponse = + delete(responseId, ResponseDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt index b683a7d69..de7f11be5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/ResponseServiceImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.emptyHandler import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler @@ -29,6 +30,7 @@ import com.openai.models.responses.ResponseRetrieveParams import com.openai.models.responses.ResponseStreamEvent import com.openai.services.blocking.responses.InputItemService import com.openai.services.blocking.responses.InputItemServiceImpl +import kotlin.jvm.optionals.getOrNull class ResponseServiceImpl internal constructor(private val clientOptions: ClientOptions) : ResponseService { @@ -151,6 +153,9 @@ class ResponseServiceImpl internal constructor(private val clientOptions: Client params: ResponseRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("responseId", params.responseId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -176,6 +181,9 @@ class ResponseServiceImpl internal constructor(private val clientOptions: Client params: ResponseDeleteParams, requestOptions: RequestOptions, ): HttpResponse { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("responseId", params.responseId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadService.kt index 47938c0ec..17bc71b0f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadService.kt @@ -49,7 +49,18 @@ interface UploadService { ): Upload /** Cancels the Upload. No Parts may be added after an Upload is cancelled. */ - fun cancel(params: UploadCancelParams): Upload = cancel(params, RequestOptions.none()) + fun cancel(uploadId: String): Upload = cancel(uploadId, UploadCancelParams.none()) + + /** @see [cancel] */ + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Upload = cancel(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [cancel] */ + fun cancel(uploadId: String, params: UploadCancelParams = UploadCancelParams.none()): Upload = + cancel(uploadId, params, RequestOptions.none()) /** @see [cancel] */ fun cancel( @@ -57,6 +68,13 @@ interface UploadService { requestOptions: RequestOptions = RequestOptions.none(), ): Upload + /** @see [cancel] */ + fun cancel(params: UploadCancelParams): Upload = cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel(uploadId: String, requestOptions: RequestOptions): Upload = + cancel(uploadId, UploadCancelParams.none(), requestOptions) + /** * Completes the [Upload](https://platform.openai.com/docs/api-reference/uploads/object). * @@ -70,6 +88,17 @@ interface UploadService { * specified when creating the Upload object. No Parts may be added after an Upload is * completed. */ + fun complete(uploadId: String, params: UploadCompleteParams): Upload = + complete(uploadId, params, RequestOptions.none()) + + /** @see [complete] */ + fun complete( + uploadId: String, + params: UploadCompleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Upload = complete(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [complete] */ fun complete(params: UploadCompleteParams): Upload = complete(params, RequestOptions.none()) /** @see [complete] */ @@ -103,8 +132,24 @@ interface UploadService { * same as [UploadService.cancel]. */ @MustBeClosed - fun cancel(params: UploadCancelParams): HttpResponseFor = - cancel(params, RequestOptions.none()) + fun cancel(uploadId: String): HttpResponseFor = + cancel(uploadId, UploadCancelParams.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + cancel(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + uploadId: String, + params: UploadCancelParams = UploadCancelParams.none(), + ): HttpResponseFor = cancel(uploadId, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -113,11 +158,35 @@ interface UploadService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [cancel] */ + @MustBeClosed + fun cancel(params: UploadCancelParams): HttpResponseFor = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel(uploadId: String, requestOptions: RequestOptions): HttpResponseFor = + cancel(uploadId, UploadCancelParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /uploads/{upload_id}/complete`, but is otherwise * the same as [UploadService.complete]. */ @MustBeClosed + fun complete(uploadId: String, params: UploadCompleteParams): HttpResponseFor = + complete(uploadId, params, RequestOptions.none()) + + /** @see [complete] */ + @MustBeClosed + fun complete( + uploadId: String, + params: UploadCompleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + complete(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [complete] */ + @MustBeClosed fun complete(params: UploadCompleteParams): HttpResponseFor = complete(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadServiceImpl.kt index d28416443..6b2d77337 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/UploadServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -21,6 +22,7 @@ import com.openai.models.uploads.UploadCompleteParams import com.openai.models.uploads.UploadCreateParams import com.openai.services.blocking.uploads.PartService import com.openai.services.blocking.uploads.PartServiceImpl +import kotlin.jvm.optionals.getOrNull class UploadServiceImpl internal constructor(private val clientOptions: ClientOptions) : UploadService { @@ -92,6 +94,9 @@ class UploadServiceImpl internal constructor(private val clientOptions: ClientOp params: UploadCancelParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("uploadId", params.uploadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -119,6 +124,9 @@ class UploadServiceImpl internal constructor(private val clientOptions: ClientOp params: UploadCompleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("uploadId", params.uploadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreService.kt index b61e9ce25..e5256a03a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreService.kt @@ -47,8 +47,22 @@ interface VectorStoreService { create(VectorStoreCreateParams.none(), requestOptions) /** Retrieves a vector store. */ - fun retrieve(params: VectorStoreRetrieveParams): VectorStore = - retrieve(params, RequestOptions.none()) + fun retrieve(vectorStoreId: String): VectorStore = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStore = + retrieve(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + ): VectorStore = retrieve(vectorStoreId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -56,8 +70,30 @@ interface VectorStoreService { requestOptions: RequestOptions = RequestOptions.none(), ): VectorStore + /** @see [retrieve] */ + fun retrieve(params: VectorStoreRetrieveParams): VectorStore = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(vectorStoreId: String, requestOptions: RequestOptions): VectorStore = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none(), requestOptions) + /** Modifies a vector store. */ - fun update(params: VectorStoreUpdateParams): VectorStore = update(params, RequestOptions.none()) + fun update(vectorStoreId: String): VectorStore = + update(vectorStoreId, VectorStoreUpdateParams.none()) + + /** @see [update] */ + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStore = update(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [update] */ + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + ): VectorStore = update(vectorStoreId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -65,6 +101,13 @@ interface VectorStoreService { requestOptions: RequestOptions = RequestOptions.none(), ): VectorStore + /** @see [update] */ + fun update(params: VectorStoreUpdateParams): VectorStore = update(params, RequestOptions.none()) + + /** @see [update] */ + fun update(vectorStoreId: String, requestOptions: RequestOptions): VectorStore = + update(vectorStoreId, VectorStoreUpdateParams.none(), requestOptions) + /** Returns a list of vector stores. */ fun list(): VectorStoreListPage = list(VectorStoreListParams.none()) @@ -83,8 +126,22 @@ interface VectorStoreService { list(VectorStoreListParams.none(), requestOptions) /** Delete a vector store. */ - fun delete(params: VectorStoreDeleteParams): VectorStoreDeleted = - delete(params, RequestOptions.none()) + fun delete(vectorStoreId: String): VectorStoreDeleted = + delete(vectorStoreId, VectorStoreDeleteParams.none()) + + /** @see [delete] */ + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreDeleted = + delete(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + ): VectorStoreDeleted = delete(vectorStoreId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -92,7 +149,27 @@ interface VectorStoreService { requestOptions: RequestOptions = RequestOptions.none(), ): VectorStoreDeleted + /** @see [delete] */ + fun delete(params: VectorStoreDeleteParams): VectorStoreDeleted = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(vectorStoreId: String, requestOptions: RequestOptions): VectorStoreDeleted = + delete(vectorStoreId, VectorStoreDeleteParams.none(), requestOptions) + /** Search a vector store for relevant chunks based on a query and file attributes filter. */ + fun search(vectorStoreId: String, params: VectorStoreSearchParams): VectorStoreSearchPage = + search(vectorStoreId, params, RequestOptions.none()) + + /** @see [search] */ + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreSearchPage = + search(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [search] */ fun search(params: VectorStoreSearchParams): VectorStoreSearchPage = search(params, RequestOptions.none()) @@ -141,8 +218,24 @@ interface VectorStoreService { * the same as [VectorStoreService.retrieve]. */ @MustBeClosed - fun retrieve(params: VectorStoreRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(vectorStoreId: String): HttpResponseFor = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + vectorStoreId: String, + params: VectorStoreRetrieveParams = VectorStoreRetrieveParams.none(), + ): HttpResponseFor = retrieve(vectorStoreId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -151,13 +244,42 @@ interface VectorStoreService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: VectorStoreRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + vectorStoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(vectorStoreId, VectorStoreRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /vector_stores/{vector_store_id}`, but is otherwise * the same as [VectorStoreService.update]. */ @MustBeClosed - fun update(params: VectorStoreUpdateParams): HttpResponseFor = - update(params, RequestOptions.none()) + fun update(vectorStoreId: String): HttpResponseFor = + update(vectorStoreId, VectorStoreUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + vectorStoreId: String, + params: VectorStoreUpdateParams = VectorStoreUpdateParams.none(), + ): HttpResponseFor = update(vectorStoreId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -166,6 +288,19 @@ interface VectorStoreService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [update] */ + @MustBeClosed + fun update(params: VectorStoreUpdateParams): HttpResponseFor = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + vectorStoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(vectorStoreId, VectorStoreUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /vector_stores`, but is otherwise the same as * [VectorStoreService.list]. @@ -196,8 +331,25 @@ interface VectorStoreService { * otherwise the same as [VectorStoreService.delete]. */ @MustBeClosed - fun delete(params: VectorStoreDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(vectorStoreId: String): HttpResponseFor = + delete(vectorStoreId, VectorStoreDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + vectorStoreId: String, + params: VectorStoreDeleteParams = VectorStoreDeleteParams.none(), + ): HttpResponseFor = + delete(vectorStoreId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -206,11 +358,41 @@ interface VectorStoreService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [delete] */ + @MustBeClosed + fun delete(params: VectorStoreDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + vectorStoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(vectorStoreId, VectorStoreDeleteParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /vector_stores/{vector_store_id}/search`, but is * otherwise the same as [VectorStoreService.search]. */ @MustBeClosed + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + ): HttpResponseFor = + search(vectorStoreId, params, RequestOptions.none()) + + /** @see [search] */ + @MustBeClosed + fun search( + vectorStoreId: String, + params: VectorStoreSearchParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + search(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [search] */ + @MustBeClosed fun search(params: VectorStoreSearchParams): HttpResponseFor = search(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreServiceImpl.kt index 5a0770917..893276794 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/VectorStoreServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -32,6 +33,7 @@ import com.openai.services.blocking.vectorstores.FileBatchService import com.openai.services.blocking.vectorstores.FileBatchServiceImpl import com.openai.services.blocking.vectorstores.FileService import com.openai.services.blocking.vectorstores.FileServiceImpl +import kotlin.jvm.optionals.getOrNull class VectorStoreServiceImpl internal constructor(private val clientOptions: ClientOptions) : VectorStoreService { @@ -149,6 +151,9 @@ class VectorStoreServiceImpl internal constructor(private val clientOptions: Cli params: VectorStoreRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -176,6 +181,9 @@ class VectorStoreServiceImpl internal constructor(private val clientOptions: Cli params: VectorStoreUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -239,6 +247,9 @@ class VectorStoreServiceImpl internal constructor(private val clientOptions: Cli params: VectorStoreDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -268,6 +279,9 @@ class VectorStoreServiceImpl internal constructor(private val clientOptions: Cli params: VectorStoreSearchParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantService.kt index 2943bacef..98d5e1950 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantService.kt @@ -31,8 +31,21 @@ interface AssistantService { ): Assistant /** Retrieves an assistant. */ - fun retrieve(params: AssistantRetrieveParams): Assistant = - retrieve(params, RequestOptions.none()) + fun retrieve(assistantId: String): Assistant = + retrieve(assistantId, AssistantRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Assistant = retrieve(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + ): Assistant = retrieve(assistantId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -40,8 +53,29 @@ interface AssistantService { requestOptions: RequestOptions = RequestOptions.none(), ): Assistant + /** @see [retrieve] */ + fun retrieve(params: AssistantRetrieveParams): Assistant = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(assistantId: String, requestOptions: RequestOptions): Assistant = + retrieve(assistantId, AssistantRetrieveParams.none(), requestOptions) + /** Modifies an assistant. */ - fun update(params: AssistantUpdateParams): Assistant = update(params, RequestOptions.none()) + fun update(assistantId: String): Assistant = update(assistantId, AssistantUpdateParams.none()) + + /** @see [update] */ + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Assistant = update(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [update] */ + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + ): Assistant = update(assistantId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -49,6 +83,13 @@ interface AssistantService { requestOptions: RequestOptions = RequestOptions.none(), ): Assistant + /** @see [update] */ + fun update(params: AssistantUpdateParams): Assistant = update(params, RequestOptions.none()) + + /** @see [update] */ + fun update(assistantId: String, requestOptions: RequestOptions): Assistant = + update(assistantId, AssistantUpdateParams.none(), requestOptions) + /** Returns a list of assistants. */ fun list(): AssistantListPage = list(AssistantListParams.none()) @@ -67,8 +108,22 @@ interface AssistantService { list(AssistantListParams.none(), requestOptions) /** Delete an assistant. */ - fun delete(params: AssistantDeleteParams): AssistantDeleted = - delete(params, RequestOptions.none()) + fun delete(assistantId: String): AssistantDeleted = + delete(assistantId, AssistantDeleteParams.none()) + + /** @see [delete] */ + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): AssistantDeleted = + delete(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + ): AssistantDeleted = delete(assistantId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -76,6 +131,14 @@ interface AssistantService { requestOptions: RequestOptions = RequestOptions.none(), ): AssistantDeleted + /** @see [delete] */ + fun delete(params: AssistantDeleteParams): AssistantDeleted = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(assistantId: String, requestOptions: RequestOptions): AssistantDeleted = + delete(assistantId, AssistantDeleteParams.none(), requestOptions) + /** A view of [AssistantService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -99,8 +162,24 @@ interface AssistantService { * same as [AssistantService.retrieve]. */ @MustBeClosed - fun retrieve(params: AssistantRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(assistantId: String): HttpResponseFor = + retrieve(assistantId, AssistantRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + assistantId: String, + params: AssistantRetrieveParams = AssistantRetrieveParams.none(), + ): HttpResponseFor = retrieve(assistantId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -109,13 +188,42 @@ interface AssistantService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: AssistantRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + assistantId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(assistantId, AssistantRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /assistants/{assistant_id}`, but is otherwise the * same as [AssistantService.update]. */ @MustBeClosed - fun update(params: AssistantUpdateParams): HttpResponseFor = - update(params, RequestOptions.none()) + fun update(assistantId: String): HttpResponseFor = + update(assistantId, AssistantUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + assistantId: String, + params: AssistantUpdateParams = AssistantUpdateParams.none(), + ): HttpResponseFor = update(assistantId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -124,6 +232,19 @@ interface AssistantService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [update] */ + @MustBeClosed + fun update(params: AssistantUpdateParams): HttpResponseFor = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + assistantId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + update(assistantId, AssistantUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /assistants`, but is otherwise the same as * [AssistantService.list]. @@ -154,8 +275,24 @@ interface AssistantService { * same as [AssistantService.delete]. */ @MustBeClosed - fun delete(params: AssistantDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(assistantId: String): HttpResponseFor = + delete(assistantId, AssistantDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().assistantId(assistantId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + assistantId: String, + params: AssistantDeleteParams = AssistantDeleteParams.none(), + ): HttpResponseFor = delete(assistantId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -163,5 +300,18 @@ interface AssistantService { params: AssistantDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [delete] */ + @MustBeClosed + fun delete(params: AssistantDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + assistantId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(assistantId, AssistantDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantServiceImpl.kt index 521543aa9..30ca6d1be 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/AssistantServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.beta import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -25,6 +26,7 @@ import com.openai.models.beta.assistants.AssistantListPageResponse import com.openai.models.beta.assistants.AssistantListParams import com.openai.models.beta.assistants.AssistantRetrieveParams import com.openai.models.beta.assistants.AssistantUpdateParams +import kotlin.jvm.optionals.getOrNull class AssistantServiceImpl internal constructor(private val clientOptions: ClientOptions) : AssistantService { @@ -109,6 +111,9 @@ class AssistantServiceImpl internal constructor(private val clientOptions: Clien params: AssistantRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("assistantId", params.assistantId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -136,6 +141,9 @@ class AssistantServiceImpl internal constructor(private val clientOptions: Clien params: AssistantUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("assistantId", params.assistantId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -203,6 +211,9 @@ class AssistantServiceImpl internal constructor(private val clientOptions: Clien params: AssistantDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("assistantId", params.assistantId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadService.kt index 8263aa931..a36261115 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadService.kt @@ -47,7 +47,20 @@ interface ThreadService { create(ThreadCreateParams.none(), requestOptions) /** Retrieves a thread. */ - fun retrieve(params: ThreadRetrieveParams): Thread = retrieve(params, RequestOptions.none()) + fun retrieve(threadId: String): Thread = retrieve(threadId, ThreadRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Thread = retrieve(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + ): Thread = retrieve(threadId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -55,8 +68,26 @@ interface ThreadService { requestOptions: RequestOptions = RequestOptions.none(), ): Thread + /** @see [retrieve] */ + fun retrieve(params: ThreadRetrieveParams): Thread = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(threadId: String, requestOptions: RequestOptions): Thread = + retrieve(threadId, ThreadRetrieveParams.none(), requestOptions) + /** Modifies a thread. */ - fun update(params: ThreadUpdateParams): Thread = update(params, RequestOptions.none()) + fun update(threadId: String): Thread = update(threadId, ThreadUpdateParams.none()) + + /** @see [update] */ + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): Thread = update(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [update] */ + fun update(threadId: String, params: ThreadUpdateParams = ThreadUpdateParams.none()): Thread = + update(threadId, params, RequestOptions.none()) /** @see [update] */ fun update( @@ -64,8 +95,28 @@ interface ThreadService { requestOptions: RequestOptions = RequestOptions.none(), ): Thread + /** @see [update] */ + fun update(params: ThreadUpdateParams): Thread = update(params, RequestOptions.none()) + + /** @see [update] */ + fun update(threadId: String, requestOptions: RequestOptions): Thread = + update(threadId, ThreadUpdateParams.none(), requestOptions) + /** Delete a thread. */ - fun delete(params: ThreadDeleteParams): ThreadDeleted = delete(params, RequestOptions.none()) + fun delete(threadId: String): ThreadDeleted = delete(threadId, ThreadDeleteParams.none()) + + /** @see [delete] */ + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ThreadDeleted = delete(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + ): ThreadDeleted = delete(threadId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -73,6 +124,13 @@ interface ThreadService { requestOptions: RequestOptions = RequestOptions.none(), ): ThreadDeleted + /** @see [delete] */ + fun delete(params: ThreadDeleteParams): ThreadDeleted = delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(threadId: String, requestOptions: RequestOptions): ThreadDeleted = + delete(threadId, ThreadDeleteParams.none(), requestOptions) + /** Create a thread and run it in one request. */ fun createAndRun(params: ThreadCreateAndRunParams): Run = createAndRun(params, RequestOptions.none()) @@ -132,8 +190,24 @@ interface ThreadService { * [ThreadService.retrieve]. */ @MustBeClosed - fun retrieve(params: ThreadRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(threadId: String): HttpResponseFor = + retrieve(threadId, ThreadRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + threadId: String, + params: ThreadRetrieveParams = ThreadRetrieveParams.none(), + ): HttpResponseFor = retrieve(threadId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -142,13 +216,39 @@ interface ThreadService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ThreadRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(threadId: String, requestOptions: RequestOptions): HttpResponseFor = + retrieve(threadId, ThreadRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /threads/{thread_id}`, but is otherwise the same as * [ThreadService.update]. */ @MustBeClosed - fun update(params: ThreadUpdateParams): HttpResponseFor = - update(params, RequestOptions.none()) + fun update(threadId: String): HttpResponseFor = + update(threadId, ThreadUpdateParams.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed + fun update( + threadId: String, + params: ThreadUpdateParams = ThreadUpdateParams.none(), + ): HttpResponseFor = update(threadId, params, RequestOptions.none()) /** @see [update] */ @MustBeClosed @@ -157,13 +257,39 @@ interface ThreadService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [update] */ + @MustBeClosed + fun update(params: ThreadUpdateParams): HttpResponseFor = + update(params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update(threadId: String, requestOptions: RequestOptions): HttpResponseFor = + update(threadId, ThreadUpdateParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /threads/{thread_id}`, but is otherwise the same * as [ThreadService.delete]. */ @MustBeClosed - fun delete(params: ThreadDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(threadId: String): HttpResponseFor = + delete(threadId, ThreadDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + threadId: String, + params: ThreadDeleteParams = ThreadDeleteParams.none(), + ): HttpResponseFor = delete(threadId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -172,6 +298,19 @@ interface ThreadService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [delete] */ + @MustBeClosed + fun delete(params: ThreadDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + threadId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(threadId, ThreadDeleteParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /threads/runs`, but is otherwise the same as * [ThreadService.createAndRun]. diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadServiceImpl.kt index 5d7ec9222..fa03e9bdb 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/ThreadServiceImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.blocking.beta import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.mapJson @@ -34,6 +35,7 @@ import com.openai.services.blocking.beta.threads.MessageService import com.openai.services.blocking.beta.threads.MessageServiceImpl import com.openai.services.blocking.beta.threads.RunService import com.openai.services.blocking.beta.threads.RunServiceImpl +import kotlin.jvm.optionals.getOrNull class ThreadServiceImpl internal constructor(private val clientOptions: ClientOptions) : ThreadService { @@ -139,6 +141,9 @@ class ThreadServiceImpl internal constructor(private val clientOptions: ClientOp params: ThreadRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -166,6 +171,9 @@ class ThreadServiceImpl internal constructor(private val clientOptions: ClientOp params: ThreadUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -194,6 +202,9 @@ class ThreadServiceImpl internal constructor(private val clientOptions: ClientOp params: ThreadDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageService.kt index 87184f956..86e7ea88e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageService.kt @@ -22,6 +22,17 @@ interface MessageService { fun withRawResponse(): WithRawResponse /** Create a message. */ + fun create(threadId: String, params: MessageCreateParams): Message = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + threadId: String, + params: MessageCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Message = create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ fun create(params: MessageCreateParams): Message = create(params, RequestOptions.none()) /** @see [create] */ @@ -31,6 +42,17 @@ interface MessageService { ): Message /** Retrieve a message. */ + fun retrieve(messageId: String, params: MessageRetrieveParams): Message = + retrieve(messageId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + messageId: String, + params: MessageRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Message = retrieve(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: MessageRetrieveParams): Message = retrieve(params, RequestOptions.none()) /** @see [retrieve] */ @@ -40,6 +62,17 @@ interface MessageService { ): Message /** Modifies a message. */ + fun update(messageId: String, params: MessageUpdateParams): Message = + update(messageId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + messageId: String, + params: MessageUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Message = update(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [update] */ fun update(params: MessageUpdateParams): Message = update(params, RequestOptions.none()) /** @see [update] */ @@ -49,7 +82,20 @@ interface MessageService { ): Message /** Returns a list of messages for a given thread. */ - fun list(params: MessageListParams): MessageListPage = list(params, RequestOptions.none()) + fun list(threadId: String): MessageListPage = list(threadId, MessageListParams.none()) + + /** @see [list] */ + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): MessageListPage = list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + ): MessageListPage = list(threadId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -57,7 +103,25 @@ interface MessageService { requestOptions: RequestOptions = RequestOptions.none(), ): MessageListPage + /** @see [list] */ + fun list(params: MessageListParams): MessageListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(threadId: String, requestOptions: RequestOptions): MessageListPage = + list(threadId, MessageListParams.none(), requestOptions) + /** Deletes a message. */ + fun delete(messageId: String, params: MessageDeleteParams): MessageDeleted = + delete(messageId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + messageId: String, + params: MessageDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): MessageDeleted = delete(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: MessageDeleteParams): MessageDeleted = delete(params, RequestOptions.none()) /** @see [delete] */ @@ -74,6 +138,20 @@ interface MessageService { * the same as [MessageService.create]. */ @MustBeClosed + fun create(threadId: String, params: MessageCreateParams): HttpResponseFor = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + threadId: String, + params: MessageCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: MessageCreateParams): HttpResponseFor = create(params, RequestOptions.none()) @@ -89,6 +167,20 @@ interface MessageService { * otherwise the same as [MessageService.retrieve]. */ @MustBeClosed + fun retrieve(messageId: String, params: MessageRetrieveParams): HttpResponseFor = + retrieve(messageId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + messageId: String, + params: MessageRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: MessageRetrieveParams): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -104,6 +196,20 @@ interface MessageService { * otherwise the same as [MessageService.update]. */ @MustBeClosed + fun update(messageId: String, params: MessageUpdateParams): HttpResponseFor = + update(messageId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + messageId: String, + params: MessageUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: MessageUpdateParams): HttpResponseFor = update(params, RequestOptions.none()) @@ -119,8 +225,24 @@ interface MessageService { * same as [MessageService.list]. */ @MustBeClosed - fun list(params: MessageListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(threadId: String): HttpResponseFor = + list(threadId, MessageListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: MessageListParams = MessageListParams.none(), + ): HttpResponseFor = list(threadId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -129,11 +251,40 @@ interface MessageService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [list] */ + @MustBeClosed + fun list(params: MessageListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + list(threadId, MessageListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /threads/{thread_id}/messages/{message_id}`, but * is otherwise the same as [MessageService.delete]. */ @MustBeClosed + fun delete( + messageId: String, + params: MessageDeleteParams, + ): HttpResponseFor = delete(messageId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + messageId: String, + params: MessageDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().messageId(messageId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete(params: MessageDeleteParams): HttpResponseFor = delete(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageServiceImpl.kt index fddd1451a..83e8bc6cb 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/MessageServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.beta.threads import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -25,6 +26,7 @@ import com.openai.models.beta.threads.messages.MessageListPageResponse import com.openai.models.beta.threads.messages.MessageListParams import com.openai.models.beta.threads.messages.MessageRetrieveParams import com.openai.models.beta.threads.messages.MessageUpdateParams +import kotlin.jvm.optionals.getOrNull class MessageServiceImpl internal constructor(private val clientOptions: ClientOptions) : MessageService { @@ -75,6 +77,9 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO params: MessageCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -103,6 +108,9 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO params: MessageRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -135,6 +143,9 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO params: MessageUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -169,6 +180,9 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO params: MessageListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -203,6 +217,9 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO params: MessageDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("messageId", params.messageId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunService.kt index 02562d7ee..0708353b4 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunService.kt @@ -27,6 +27,17 @@ interface RunService { fun steps(): StepService /** Create a run. */ + fun create(threadId: String, params: RunCreateParams): Run = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Run = create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ fun create(params: RunCreateParams): Run = create(params, RequestOptions.none()) /** @see [create] */ @@ -34,6 +45,23 @@ interface RunService { /** Create a run. */ @MustBeClosed + fun createStreaming( + threadId: String, + params: RunCreateParams, + ): StreamResponse = + createStreaming(threadId, params, RequestOptions.none()) + + /** @see [createStreaming] */ + @MustBeClosed + fun createStreaming( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse = + createStreaming(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [createStreaming] */ + @MustBeClosed fun createStreaming(params: RunCreateParams): StreamResponse = createStreaming(params, RequestOptions.none()) @@ -45,6 +73,17 @@ interface RunService { ): StreamResponse /** Retrieves a run. */ + fun retrieve(runId: String, params: RunRetrieveParams): Run = + retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Run = retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: RunRetrieveParams): Run = retrieve(params, RequestOptions.none()) /** @see [retrieve] */ @@ -54,13 +93,35 @@ interface RunService { ): Run /** Modifies a run. */ + fun update(runId: String, params: RunUpdateParams): Run = + update(runId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + runId: String, + params: RunUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Run = update(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [update] */ fun update(params: RunUpdateParams): Run = update(params, RequestOptions.none()) /** @see [update] */ fun update(params: RunUpdateParams, requestOptions: RequestOptions = RequestOptions.none()): Run /** Returns a list of runs belonging to a thread. */ - fun list(params: RunListParams): RunListPage = list(params, RequestOptions.none()) + fun list(threadId: String): RunListPage = list(threadId, RunListParams.none()) + + /** @see [list] */ + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): RunListPage = list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + fun list(threadId: String, params: RunListParams = RunListParams.none()): RunListPage = + list(threadId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -68,7 +129,25 @@ interface RunService { requestOptions: RequestOptions = RequestOptions.none(), ): RunListPage + /** @see [list] */ + fun list(params: RunListParams): RunListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(threadId: String, requestOptions: RequestOptions): RunListPage = + list(threadId, RunListParams.none(), requestOptions) + /** Cancels a run that is `in_progress`. */ + fun cancel(runId: String, params: RunCancelParams): Run = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Run = cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ fun cancel(params: RunCancelParams): Run = cancel(params, RequestOptions.none()) /** @see [cancel] */ @@ -79,6 +158,17 @@ interface RunService { * `submit_tool_outputs`, this endpoint can be used to submit the outputs from the tool calls * once they're all completed. All outputs must be submitted in a single request. */ + fun submitToolOutputs(runId: String, params: RunSubmitToolOutputsParams): Run = + submitToolOutputs(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputs] */ + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): Run = submitToolOutputs(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputs] */ fun submitToolOutputs(params: RunSubmitToolOutputsParams): Run = submitToolOutputs(params, RequestOptions.none()) @@ -94,6 +184,23 @@ interface RunService { * once they're all completed. All outputs must be submitted in a single request. */ @MustBeClosed + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + ): StreamResponse = + submitToolOutputsStreaming(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputsStreaming] */ + @MustBeClosed + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StreamResponse = + submitToolOutputsStreaming(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputsStreaming] */ + @MustBeClosed fun submitToolOutputsStreaming( params: RunSubmitToolOutputsParams ): StreamResponse = @@ -116,6 +223,20 @@ interface RunService { * same as [RunService.create]. */ @MustBeClosed + fun create(threadId: String, params: RunCreateParams): HttpResponseFor = + create(threadId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: RunCreateParams): HttpResponseFor = create(params, RequestOptions.none()) @@ -131,6 +252,23 @@ interface RunService { * same as [RunService.createStreaming]. */ @MustBeClosed + fun createStreaming( + threadId: String, + params: RunCreateParams, + ): HttpResponseFor> = + createStreaming(threadId, params, RequestOptions.none()) + + /** @see [createStreaming] */ + @MustBeClosed + fun createStreaming( + threadId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + createStreaming(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [createStreaming] */ + @MustBeClosed fun createStreaming( params: RunCreateParams ): HttpResponseFor> = @@ -148,6 +286,19 @@ interface RunService { * otherwise the same as [RunService.retrieve]. */ @MustBeClosed + fun retrieve(runId: String, params: RunRetrieveParams): HttpResponseFor = + retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: RunRetrieveParams): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -163,6 +314,19 @@ interface RunService { * otherwise the same as [RunService.update]. */ @MustBeClosed + fun update(runId: String, params: RunUpdateParams): HttpResponseFor = + update(runId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + runId: String, + params: RunUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = update(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: RunUpdateParams): HttpResponseFor = update(params, RequestOptions.none()) @@ -178,8 +342,24 @@ interface RunService { * same as [RunService.list]. */ @MustBeClosed - fun list(params: RunListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(threadId: String): HttpResponseFor = + list(threadId, RunListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().threadId(threadId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + threadId: String, + params: RunListParams = RunListParams.none(), + ): HttpResponseFor = list(threadId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -188,11 +368,34 @@ interface RunService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [list] */ + @MustBeClosed + fun list(params: RunListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list(threadId: String, requestOptions: RequestOptions): HttpResponseFor = + list(threadId, RunListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /threads/{thread_id}/runs/{run_id}/cancel`, but is * otherwise the same as [RunService.cancel]. */ @MustBeClosed + fun cancel(runId: String, params: RunCancelParams): HttpResponseFor = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed fun cancel(params: RunCancelParams): HttpResponseFor = cancel(params, RequestOptions.none()) @@ -209,6 +412,22 @@ interface RunService { * [RunService.submitToolOutputs]. */ @MustBeClosed + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + ): HttpResponseFor = submitToolOutputs(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputs] */ + @MustBeClosed + fun submitToolOutputs( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + submitToolOutputs(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputs] */ + @MustBeClosed fun submitToolOutputs(params: RunSubmitToolOutputsParams): HttpResponseFor = submitToolOutputs(params, RequestOptions.none()) @@ -225,6 +444,23 @@ interface RunService { * [RunService.submitToolOutputsStreaming]. */ @MustBeClosed + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + ): HttpResponseFor> = + submitToolOutputsStreaming(runId, params, RequestOptions.none()) + + /** @see [submitToolOutputsStreaming] */ + @MustBeClosed + fun submitToolOutputsStreaming( + runId: String, + params: RunSubmitToolOutputsParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor> = + submitToolOutputsStreaming(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [submitToolOutputsStreaming] */ + @MustBeClosed fun submitToolOutputsStreaming( params: RunSubmitToolOutputsParams ): HttpResponseFor> = diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunServiceImpl.kt index 0d7f999db..0f7f56e81 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/RunServiceImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.blocking.beta.threads import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.mapJson @@ -33,6 +34,7 @@ import com.openai.models.beta.threads.runs.RunSubmitToolOutputsParams import com.openai.models.beta.threads.runs.RunUpdateParams import com.openai.services.blocking.beta.threads.runs.StepService import com.openai.services.blocking.beta.threads.runs.StepServiceImpl +import kotlin.jvm.optionals.getOrNull class RunServiceImpl internal constructor(private val clientOptions: ClientOptions) : RunService { @@ -110,6 +112,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -144,6 +149,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunCreateParams, requestOptions: RequestOptions, ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -187,6 +195,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -214,6 +225,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -243,6 +257,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("threadId", params.threadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -277,6 +294,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunCancelParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -311,6 +331,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunSubmitToolOutputsParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -348,6 +371,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunSubmitToolOutputsParams, requestOptions: RequestOptions, ): HttpResponseFor> { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepService.kt index 5b4bf4718..6e5270de1 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepService.kt @@ -18,6 +18,17 @@ interface StepService { fun withRawResponse(): WithRawResponse /** Retrieves a run step. */ + fun retrieve(stepId: String, params: StepRetrieveParams): RunStep = + retrieve(stepId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + stepId: String, + params: StepRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): RunStep = retrieve(params.toBuilder().stepId(stepId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: StepRetrieveParams): RunStep = retrieve(params, RequestOptions.none()) /** @see [retrieve] */ @@ -27,6 +38,17 @@ interface StepService { ): RunStep /** Returns a list of run steps belonging to a run. */ + fun list(runId: String, params: StepListParams): StepListPage = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + fun list( + runId: String, + params: StepListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StepListPage = list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ fun list(params: StepListParams): StepListPage = list(params, RequestOptions.none()) /** @see [list] */ @@ -43,6 +65,20 @@ interface StepService { * but is otherwise the same as [StepService.retrieve]. */ @MustBeClosed + fun retrieve(stepId: String, params: StepRetrieveParams): HttpResponseFor = + retrieve(stepId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + stepId: String, + params: StepRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().stepId(stepId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: StepRetrieveParams): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -58,6 +94,20 @@ interface StepService { * otherwise the same as [StepService.list]. */ @MustBeClosed + fun list(runId: String, params: StepListParams): HttpResponseFor = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + runId: String, + params: StepListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed fun list(params: StepListParams): HttpResponseFor = list(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepServiceImpl.kt index e4d41faf6..bc2477b00 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/beta/threads/runs/StepServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.beta.threads.runs import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -20,6 +21,7 @@ import com.openai.models.beta.threads.runs.steps.StepListPage import com.openai.models.beta.threads.runs.steps.StepListPageResponse import com.openai.models.beta.threads.runs.steps.StepListParams import com.openai.models.beta.threads.runs.steps.StepRetrieveParams +import kotlin.jvm.optionals.getOrNull class StepServiceImpl internal constructor(private val clientOptions: ClientOptions) : StepService { @@ -54,6 +56,9 @@ class StepServiceImpl internal constructor(private val clientOptions: ClientOpti params: StepRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("stepId", params.stepId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -89,6 +94,9 @@ class StepServiceImpl internal constructor(private val clientOptions: ClientOpti params: StepListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionService.kt index 3f46a970e..43f372d2a 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionService.kt @@ -15,6 +15,8 @@ import com.openai.models.chat.completions.ChatCompletionListPage import com.openai.models.chat.completions.ChatCompletionListParams import com.openai.models.chat.completions.ChatCompletionRetrieveParams import com.openai.models.chat.completions.ChatCompletionUpdateParams +import com.openai.models.chat.completions.StructuredChatCompletion +import com.openai.models.chat.completions.StructuredChatCompletionCreateParams import com.openai.services.blocking.chat.completions.MessageService interface ChatCompletionService { @@ -53,6 +55,30 @@ interface ChatCompletionService { requestOptions: RequestOptions = RequestOptions.none(), ): ChatCompletion + /** + * Creates a model response for the given chat conversation. The model's structured output in + * JSON form will be deserialized automatically into an instance of the class `T`. See the SDK + * documentation for more details. + * + * @see create + */ + fun create( + params: StructuredChatCompletionCreateParams + ): StructuredChatCompletion = create(params, RequestOptions.none()) + + /** + * Creates a model response for the given chat conversation. The model's structured output in + * JSON form will be deserialized automatically into an instance of the class `T`. See the SDK + * documentation for more details. + * + * @see create + */ + fun create( + params: StructuredChatCompletionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): StructuredChatCompletion = + StructuredChatCompletion(params.responseType, create(params.rawParams, requestOptions)) + /** * **Starting a new project?** We recommend trying * [Responses](https://platform.openai.com/docs/api-reference/responses) to take advantage of @@ -86,8 +112,22 @@ interface ChatCompletionService { * Get a stored chat completion. Only Chat Completions that have been created with the `store` * parameter set to `true` will be returned. */ - fun retrieve(params: ChatCompletionRetrieveParams): ChatCompletion = - retrieve(params, RequestOptions.none()) + fun retrieve(completionId: String): ChatCompletion = + retrieve(completionId, ChatCompletionRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ChatCompletion = + retrieve(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + ): ChatCompletion = retrieve(completionId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -95,11 +135,31 @@ interface ChatCompletionService { requestOptions: RequestOptions = RequestOptions.none(), ): ChatCompletion + /** @see [retrieve] */ + fun retrieve(params: ChatCompletionRetrieveParams): ChatCompletion = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(completionId: String, requestOptions: RequestOptions): ChatCompletion = + retrieve(completionId, ChatCompletionRetrieveParams.none(), requestOptions) + /** * Modify a stored chat completion. Only Chat Completions that have been created with the * `store` parameter set to `true` can be modified. Currently, the only supported modification * is to update the `metadata` field. */ + fun update(completionId: String, params: ChatCompletionUpdateParams): ChatCompletion = + update(completionId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): ChatCompletion = + update(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [update] */ fun update(params: ChatCompletionUpdateParams): ChatCompletion = update(params, RequestOptions.none()) @@ -134,8 +194,22 @@ interface ChatCompletionService { * Delete a stored chat completion. Only Chat Completions that have been created with the * `store` parameter set to `true` can be deleted. */ - fun delete(params: ChatCompletionDeleteParams): ChatCompletionDeleted = - delete(params, RequestOptions.none()) + fun delete(completionId: String): ChatCompletionDeleted = + delete(completionId, ChatCompletionDeleteParams.none()) + + /** @see [delete] */ + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): ChatCompletionDeleted = + delete(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [delete] */ + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + ): ChatCompletionDeleted = delete(completionId, params, RequestOptions.none()) /** @see [delete] */ fun delete( @@ -143,6 +217,14 @@ interface ChatCompletionService { requestOptions: RequestOptions = RequestOptions.none(), ): ChatCompletionDeleted + /** @see [delete] */ + fun delete(params: ChatCompletionDeleteParams): ChatCompletionDeleted = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + fun delete(completionId: String, requestOptions: RequestOptions): ChatCompletionDeleted = + delete(completionId, ChatCompletionDeleteParams.none(), requestOptions) + /** * A view of [ChatCompletionService] that provides access to raw HTTP responses for each method. */ @@ -187,8 +269,24 @@ interface ChatCompletionService { * the same as [ChatCompletionService.retrieve]. */ @MustBeClosed - fun retrieve(params: ChatCompletionRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(completionId: String): HttpResponseFor = + retrieve(completionId, ChatCompletionRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + completionId: String, + params: ChatCompletionRetrieveParams = ChatCompletionRetrieveParams.none(), + ): HttpResponseFor = retrieve(completionId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -197,11 +295,40 @@ interface ChatCompletionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: ChatCompletionRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + completionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(completionId, ChatCompletionRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `post /chat/completions/{completion_id}`, but is * otherwise the same as [ChatCompletionService.update]. */ @MustBeClosed + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + ): HttpResponseFor = update(completionId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + completionId: String, + params: ChatCompletionUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: ChatCompletionUpdateParams): HttpResponseFor = update(params, RequestOptions.none()) @@ -242,8 +369,25 @@ interface ChatCompletionService { * otherwise the same as [ChatCompletionService.delete]. */ @MustBeClosed - fun delete(params: ChatCompletionDeleteParams): HttpResponseFor = - delete(params, RequestOptions.none()) + fun delete(completionId: String): HttpResponseFor = + delete(completionId, ChatCompletionDeleteParams.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed + fun delete( + completionId: String, + params: ChatCompletionDeleteParams = ChatCompletionDeleteParams.none(), + ): HttpResponseFor = + delete(completionId, params, RequestOptions.none()) /** @see [delete] */ @MustBeClosed @@ -251,5 +395,18 @@ interface ChatCompletionService { params: ChatCompletionDeleteParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [delete] */ + @MustBeClosed + fun delete(params: ChatCompletionDeleteParams): HttpResponseFor = + delete(params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + completionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + delete(completionId, ChatCompletionDeleteParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceImpl.kt index 0bffd8dfd..b07c2c6c5 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceImpl.kt @@ -5,6 +5,7 @@ package com.openai.services.blocking.chat import com.openai.core.ClientOptions import com.openai.core.JsonValue import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.mapJson @@ -174,6 +175,9 @@ class ChatCompletionServiceImpl internal constructor(private val clientOptions: params: ChatCompletionRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -200,6 +204,9 @@ class ChatCompletionServiceImpl internal constructor(private val clientOptions: params: ChatCompletionUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -266,6 +273,9 @@ class ChatCompletionServiceImpl internal constructor(private val clientOptions: params: ChatCompletionDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageService.kt index b1161981b..d4fc968ca 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageService.kt @@ -19,7 +19,20 @@ interface MessageService { * Get the messages in a stored chat completion. Only Chat Completions that have been created * with the `store` parameter set to `true` will be returned. */ - fun list(params: MessageListParams): MessageListPage = list(params, RequestOptions.none()) + fun list(completionId: String): MessageListPage = list(completionId, MessageListParams.none()) + + /** @see [list] */ + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): MessageListPage = list(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [list] */ + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + ): MessageListPage = list(completionId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -27,6 +40,13 @@ interface MessageService { requestOptions: RequestOptions = RequestOptions.none(), ): MessageListPage + /** @see [list] */ + fun list(params: MessageListParams): MessageListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(completionId: String, requestOptions: RequestOptions): MessageListPage = + list(completionId, MessageListParams.none(), requestOptions) + /** A view of [MessageService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -35,8 +55,24 @@ interface MessageService { * otherwise the same as [MessageService.list]. */ @MustBeClosed - fun list(params: MessageListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(completionId: String): HttpResponseFor = + list(completionId, MessageListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().completionId(completionId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + completionId: String, + params: MessageListParams = MessageListParams.none(), + ): HttpResponseFor = list(completionId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -44,5 +80,18 @@ interface MessageService { params: MessageListParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [list] */ + @MustBeClosed + fun list(params: MessageListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + completionId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + list(completionId, MessageListParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageServiceImpl.kt index c87f53ee9..52b267d3d 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/chat/completions/MessageServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.chat.completions import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -17,6 +18,7 @@ import com.openai.models.ErrorObject import com.openai.models.chat.completions.messages.MessageListPage import com.openai.models.chat.completions.messages.MessageListPageResponse import com.openai.models.chat.completions.messages.MessageListParams +import kotlin.jvm.optionals.getOrNull class MessageServiceImpl internal constructor(private val clientOptions: ClientOptions) : MessageService { @@ -44,6 +46,9 @@ class MessageServiceImpl internal constructor(private val clientOptions: ClientO params: MessageListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("completionId", params.completionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunService.kt index c604c6c21..fff6cf21f 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunService.kt @@ -27,6 +27,17 @@ interface RunService { fun outputItems(): OutputItemService /** Create a new evaluation run. This is the endpoint that will kick off grading. */ + fun create(evalId: String, params: RunCreateParams): RunCreateResponse = + create(evalId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + evalId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): RunCreateResponse = create(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [create] */ fun create(params: RunCreateParams): RunCreateResponse = create(params, RequestOptions.none()) /** @see [create] */ @@ -36,6 +47,17 @@ interface RunService { ): RunCreateResponse /** Get an evaluation run by ID. */ + fun retrieve(runId: String, params: RunRetrieveParams): RunRetrieveResponse = + retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): RunRetrieveResponse = retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: RunRetrieveParams): RunRetrieveResponse = retrieve(params, RequestOptions.none()) @@ -46,7 +68,18 @@ interface RunService { ): RunRetrieveResponse /** Get a list of runs for an evaluation. */ - fun list(params: RunListParams): RunListPage = list(params, RequestOptions.none()) + fun list(evalId: String): RunListPage = list(evalId, RunListParams.none()) + + /** @see [list] */ + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): RunListPage = list(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [list] */ + fun list(evalId: String, params: RunListParams = RunListParams.none()): RunListPage = + list(evalId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -54,7 +87,25 @@ interface RunService { requestOptions: RequestOptions = RequestOptions.none(), ): RunListPage + /** @see [list] */ + fun list(params: RunListParams): RunListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(evalId: String, requestOptions: RequestOptions): RunListPage = + list(evalId, RunListParams.none(), requestOptions) + /** Delete an eval run. */ + fun delete(runId: String, params: RunDeleteParams): RunDeleteResponse = + delete(runId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + runId: String, + params: RunDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): RunDeleteResponse = delete(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: RunDeleteParams): RunDeleteResponse = delete(params, RequestOptions.none()) /** @see [delete] */ @@ -64,6 +115,17 @@ interface RunService { ): RunDeleteResponse /** Cancel an ongoing evaluation run. */ + fun cancel(runId: String, params: RunCancelParams): RunCancelResponse = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): RunCancelResponse = cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ fun cancel(params: RunCancelParams): RunCancelResponse = cancel(params, RequestOptions.none()) /** @see [cancel] */ @@ -82,6 +144,20 @@ interface RunService { * as [RunService.create]. */ @MustBeClosed + fun create(evalId: String, params: RunCreateParams): HttpResponseFor = + create(evalId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + evalId: String, + params: RunCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: RunCreateParams): HttpResponseFor = create(params, RequestOptions.none()) @@ -97,6 +173,22 @@ interface RunService { * the same as [RunService.retrieve]. */ @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + ): HttpResponseFor = retrieve(runId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + runId: String, + params: RunRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: RunRetrieveParams): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -112,8 +204,23 @@ interface RunService { * [RunService.list]. */ @MustBeClosed - fun list(params: RunListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(evalId: String): HttpResponseFor = list(evalId, RunListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().evalId(evalId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + evalId: String, + params: RunListParams = RunListParams.none(), + ): HttpResponseFor = list(evalId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -122,11 +229,35 @@ interface RunService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [list] */ + @MustBeClosed + fun list(params: RunListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list(evalId: String, requestOptions: RequestOptions): HttpResponseFor = + list(evalId, RunListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete /evals/{eval_id}/runs/{run_id}`, but is otherwise * the same as [RunService.delete]. */ @MustBeClosed + fun delete(runId: String, params: RunDeleteParams): HttpResponseFor = + delete(runId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + runId: String, + params: RunDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete(params: RunDeleteParams): HttpResponseFor = delete(params, RequestOptions.none()) @@ -142,6 +273,20 @@ interface RunService { * the same as [RunService.cancel]. */ @MustBeClosed + fun cancel(runId: String, params: RunCancelParams): HttpResponseFor = + cancel(runId, params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + runId: String, + params: RunCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + cancel(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed fun cancel(params: RunCancelParams): HttpResponseFor = cancel(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunServiceImpl.kt index aa985644a..ee64dae6e 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/RunServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.evals import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -28,6 +29,7 @@ import com.openai.models.evals.runs.RunRetrieveParams import com.openai.models.evals.runs.RunRetrieveResponse import com.openai.services.blocking.evals.runs.OutputItemService import com.openai.services.blocking.evals.runs.OutputItemServiceImpl +import kotlin.jvm.optionals.getOrNull class RunServiceImpl internal constructor(private val clientOptions: ClientOptions) : RunService { @@ -91,6 +93,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -119,6 +124,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -146,6 +154,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("evalId", params.evalId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -179,6 +190,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -206,6 +220,9 @@ class RunServiceImpl internal constructor(private val clientOptions: ClientOptio params: RunCancelParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemService.kt index 5a1750da2..59468f9e7 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemService.kt @@ -18,6 +18,20 @@ interface OutputItemService { fun withRawResponse(): WithRawResponse /** Get an evaluation run output item by ID. */ + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + ): OutputItemRetrieveResponse = retrieve(outputItemId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): OutputItemRetrieveResponse = + retrieve(params.toBuilder().outputItemId(outputItemId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: OutputItemRetrieveParams): OutputItemRetrieveResponse = retrieve(params, RequestOptions.none()) @@ -28,6 +42,17 @@ interface OutputItemService { ): OutputItemRetrieveResponse /** Get a list of output items for an evaluation run. */ + fun list(runId: String, params: OutputItemListParams): OutputItemListPage = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + fun list( + runId: String, + params: OutputItemListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): OutputItemListPage = list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ fun list(params: OutputItemListParams): OutputItemListPage = list(params, RequestOptions.none()) /** @see [list] */ @@ -45,6 +70,23 @@ interface OutputItemService { * as [OutputItemService.retrieve]. */ @MustBeClosed + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + ): HttpResponseFor = + retrieve(outputItemId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + outputItemId: String, + params: OutputItemRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().outputItemId(outputItemId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve( params: OutputItemRetrieveParams ): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -61,6 +103,20 @@ interface OutputItemService { * otherwise the same as [OutputItemService.list]. */ @MustBeClosed + fun list(runId: String, params: OutputItemListParams): HttpResponseFor = + list(runId, params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + runId: String, + params: OutputItemListParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().runId(runId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed fun list(params: OutputItemListParams): HttpResponseFor = list(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemServiceImpl.kt index cce944dd3..de2cfba3b 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/evals/runs/OutputItemServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.evals.runs import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -19,6 +20,7 @@ import com.openai.models.evals.runs.outputitems.OutputItemListPageResponse import com.openai.models.evals.runs.outputitems.OutputItemListParams import com.openai.models.evals.runs.outputitems.OutputItemRetrieveParams import com.openai.models.evals.runs.outputitems.OutputItemRetrieveResponse +import kotlin.jvm.optionals.getOrNull class OutputItemServiceImpl internal constructor(private val clientOptions: ClientOptions) : OutputItemService { @@ -56,6 +58,9 @@ class OutputItemServiceImpl internal constructor(private val clientOptions: Clie params: OutputItemRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("outputItemId", params.outputItemId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -90,6 +95,9 @@ class OutputItemServiceImpl internal constructor(private val clientOptions: Clie params: OutputItemListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("runId", params.runId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/AlphaService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/AlphaService.kt new file mode 100644 index 000000000..6f8923640 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/AlphaService.kt @@ -0,0 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning + +import com.openai.services.blocking.finetuning.alpha.GraderService + +interface AlphaService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + fun graders(): GraderService + + /** A view of [AlphaService] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse { + + fun graders(): GraderService.WithRawResponse + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/AlphaServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/AlphaServiceImpl.kt new file mode 100644 index 000000000..372892c0a --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/AlphaServiceImpl.kt @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning + +import com.openai.core.ClientOptions +import com.openai.services.blocking.finetuning.alpha.GraderService +import com.openai.services.blocking.finetuning.alpha.GraderServiceImpl + +class AlphaServiceImpl internal constructor(private val clientOptions: ClientOptions) : + AlphaService { + + private val withRawResponse: AlphaService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + private val graders: GraderService by lazy { GraderServiceImpl(clientOptions) } + + override fun withRawResponse(): AlphaService.WithRawResponse = withRawResponse + + override fun graders(): GraderService = graders + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + AlphaService.WithRawResponse { + + private val graders: GraderService.WithRawResponse by lazy { + GraderServiceImpl.WithRawResponseImpl(clientOptions) + } + + override fun graders(): GraderService.WithRawResponse = graders + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobService.kt index 1985fe059..785543c00 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobService.kt @@ -12,6 +12,8 @@ import com.openai.models.finetuning.jobs.JobListEventsPage import com.openai.models.finetuning.jobs.JobListEventsParams import com.openai.models.finetuning.jobs.JobListPage import com.openai.models.finetuning.jobs.JobListParams +import com.openai.models.finetuning.jobs.JobPauseParams +import com.openai.models.finetuning.jobs.JobResumeParams import com.openai.models.finetuning.jobs.JobRetrieveParams import com.openai.services.blocking.finetuning.jobs.CheckpointService @@ -46,7 +48,22 @@ interface JobService { * * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) */ - fun retrieve(params: JobRetrieveParams): FineTuningJob = retrieve(params, RequestOptions.none()) + fun retrieve(fineTuningJobId: String): FineTuningJob = + retrieve(fineTuningJobId, JobRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FineTuningJob = + retrieve(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [retrieve] */ + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + ): FineTuningJob = retrieve(fineTuningJobId, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -54,6 +71,13 @@ interface JobService { requestOptions: RequestOptions = RequestOptions.none(), ): FineTuningJob + /** @see [retrieve] */ + fun retrieve(params: JobRetrieveParams): FineTuningJob = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve(fineTuningJobId: String, requestOptions: RequestOptions): FineTuningJob = + retrieve(fineTuningJobId, JobRetrieveParams.none(), requestOptions) + /** List your organization's fine-tuning jobs */ fun list(): JobListPage = list(JobListParams.none()) @@ -72,7 +96,22 @@ interface JobService { list(JobListParams.none(), requestOptions) /** Immediately cancel a fine-tune job. */ - fun cancel(params: JobCancelParams): FineTuningJob = cancel(params, RequestOptions.none()) + fun cancel(fineTuningJobId: String): FineTuningJob = + cancel(fineTuningJobId, JobCancelParams.none()) + + /** @see [cancel] */ + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FineTuningJob = + cancel(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [cancel] */ + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + ): FineTuningJob = cancel(fineTuningJobId, params, RequestOptions.none()) /** @see [cancel] */ fun cancel( @@ -80,9 +119,30 @@ interface JobService { requestOptions: RequestOptions = RequestOptions.none(), ): FineTuningJob + /** @see [cancel] */ + fun cancel(params: JobCancelParams): FineTuningJob = cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel(fineTuningJobId: String, requestOptions: RequestOptions): FineTuningJob = + cancel(fineTuningJobId, JobCancelParams.none(), requestOptions) + /** Get status updates for a fine-tuning job. */ - fun listEvents(params: JobListEventsParams): JobListEventsPage = - listEvents(params, RequestOptions.none()) + fun listEvents(fineTuningJobId: String): JobListEventsPage = + listEvents(fineTuningJobId, JobListEventsParams.none()) + + /** @see [listEvents] */ + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): JobListEventsPage = + listEvents(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [listEvents] */ + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + ): JobListEventsPage = listEvents(fineTuningJobId, params, RequestOptions.none()) /** @see [listEvents] */ fun listEvents( @@ -90,6 +150,76 @@ interface JobService { requestOptions: RequestOptions = RequestOptions.none(), ): JobListEventsPage + /** @see [listEvents] */ + fun listEvents(params: JobListEventsParams): JobListEventsPage = + listEvents(params, RequestOptions.none()) + + /** @see [listEvents] */ + fun listEvents(fineTuningJobId: String, requestOptions: RequestOptions): JobListEventsPage = + listEvents(fineTuningJobId, JobListEventsParams.none(), requestOptions) + + /** Pause a fine-tune job. */ + fun pause(fineTuningJobId: String): FineTuningJob = + pause(fineTuningJobId, JobPauseParams.none()) + + /** @see [pause] */ + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FineTuningJob = + pause(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [pause] */ + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + ): FineTuningJob = pause(fineTuningJobId, params, RequestOptions.none()) + + /** @see [pause] */ + fun pause( + params: JobPauseParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FineTuningJob + + /** @see [pause] */ + fun pause(params: JobPauseParams): FineTuningJob = pause(params, RequestOptions.none()) + + /** @see [pause] */ + fun pause(fineTuningJobId: String, requestOptions: RequestOptions): FineTuningJob = + pause(fineTuningJobId, JobPauseParams.none(), requestOptions) + + /** Resume a fine-tune job. */ + fun resume(fineTuningJobId: String): FineTuningJob = + resume(fineTuningJobId, JobResumeParams.none()) + + /** @see [resume] */ + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FineTuningJob = + resume(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [resume] */ + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + ): FineTuningJob = resume(fineTuningJobId, params, RequestOptions.none()) + + /** @see [resume] */ + fun resume( + params: JobResumeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FineTuningJob + + /** @see [resume] */ + fun resume(params: JobResumeParams): FineTuningJob = resume(params, RequestOptions.none()) + + /** @see [resume] */ + fun resume(fineTuningJobId: String, requestOptions: RequestOptions): FineTuningJob = + resume(fineTuningJobId, JobResumeParams.none(), requestOptions) + /** A view of [JobService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -115,8 +245,24 @@ interface JobService { * otherwise the same as [JobService.retrieve]. */ @MustBeClosed - fun retrieve(params: JobRetrieveParams): HttpResponseFor = - retrieve(params, RequestOptions.none()) + fun retrieve(fineTuningJobId: String): HttpResponseFor = + retrieve(fineTuningJobId, JobRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTuningJobId: String, + params: JobRetrieveParams = JobRetrieveParams.none(), + ): HttpResponseFor = retrieve(fineTuningJobId, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -125,6 +271,19 @@ interface JobService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve(params: JobRetrieveParams): HttpResponseFor = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(fineTuningJobId, JobRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /fine_tuning/jobs`, but is otherwise the same as * [JobService.list]. @@ -153,8 +312,24 @@ interface JobService { * is otherwise the same as [JobService.cancel]. */ @MustBeClosed - fun cancel(params: JobCancelParams): HttpResponseFor = - cancel(params, RequestOptions.none()) + fun cancel(fineTuningJobId: String): HttpResponseFor = + cancel(fineTuningJobId, JobCancelParams.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + cancel(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + fineTuningJobId: String, + params: JobCancelParams = JobCancelParams.none(), + ): HttpResponseFor = cancel(fineTuningJobId, params, RequestOptions.none()) /** @see [cancel] */ @MustBeClosed @@ -163,13 +338,43 @@ interface JobService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [cancel] */ + @MustBeClosed + fun cancel(params: JobCancelParams): HttpResponseFor = + cancel(params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + cancel(fineTuningJobId, JobCancelParams.none(), requestOptions) + /** * Returns a raw HTTP response for `get /fine_tuning/jobs/{fine_tuning_job_id}/events`, but * is otherwise the same as [JobService.listEvents]. */ @MustBeClosed - fun listEvents(params: JobListEventsParams): HttpResponseFor = - listEvents(params, RequestOptions.none()) + fun listEvents(fineTuningJobId: String): HttpResponseFor = + listEvents(fineTuningJobId, JobListEventsParams.none()) + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + listEvents(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + fineTuningJobId: String, + params: JobListEventsParams = JobListEventsParams.none(), + ): HttpResponseFor = + listEvents(fineTuningJobId, params, RequestOptions.none()) /** @see [listEvents] */ @MustBeClosed @@ -177,5 +382,106 @@ interface JobService { params: JobListEventsParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents(params: JobListEventsParams): HttpResponseFor = + listEvents(params, RequestOptions.none()) + + /** @see [listEvents] */ + @MustBeClosed + fun listEvents( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + listEvents(fineTuningJobId, JobListEventsParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /fine_tuning/jobs/{fine_tuning_job_id}/pause`, but + * is otherwise the same as [JobService.pause]. + */ + @MustBeClosed + fun pause(fineTuningJobId: String): HttpResponseFor = + pause(fineTuningJobId, JobPauseParams.none()) + + /** @see [pause] */ + @MustBeClosed + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + pause(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [pause] */ + @MustBeClosed + fun pause( + fineTuningJobId: String, + params: JobPauseParams = JobPauseParams.none(), + ): HttpResponseFor = pause(fineTuningJobId, params, RequestOptions.none()) + + /** @see [pause] */ + @MustBeClosed + fun pause( + params: JobPauseParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see [pause] */ + @MustBeClosed + fun pause(params: JobPauseParams): HttpResponseFor = + pause(params, RequestOptions.none()) + + /** @see [pause] */ + @MustBeClosed + fun pause( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + pause(fineTuningJobId, JobPauseParams.none(), requestOptions) + + /** + * Returns a raw HTTP response for `post /fine_tuning/jobs/{fine_tuning_job_id}/resume`, but + * is otherwise the same as [JobService.resume]. + */ + @MustBeClosed + fun resume(fineTuningJobId: String): HttpResponseFor = + resume(fineTuningJobId, JobResumeParams.none()) + + /** @see [resume] */ + @MustBeClosed + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + resume(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [resume] */ + @MustBeClosed + fun resume( + fineTuningJobId: String, + params: JobResumeParams = JobResumeParams.none(), + ): HttpResponseFor = resume(fineTuningJobId, params, RequestOptions.none()) + + /** @see [resume] */ + @MustBeClosed + fun resume( + params: JobResumeParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** @see [resume] */ + @MustBeClosed + fun resume(params: JobResumeParams): HttpResponseFor = + resume(params, RequestOptions.none()) + + /** @see [resume] */ + @MustBeClosed + fun resume( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + resume(fineTuningJobId, JobResumeParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobServiceImpl.kt index 64319c98b..ba95b5d36 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/JobServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.finetuning import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -24,9 +25,12 @@ import com.openai.models.finetuning.jobs.JobListEventsParams import com.openai.models.finetuning.jobs.JobListPage import com.openai.models.finetuning.jobs.JobListPageResponse import com.openai.models.finetuning.jobs.JobListParams +import com.openai.models.finetuning.jobs.JobPauseParams +import com.openai.models.finetuning.jobs.JobResumeParams import com.openai.models.finetuning.jobs.JobRetrieveParams import com.openai.services.blocking.finetuning.jobs.CheckpointService import com.openai.services.blocking.finetuning.jobs.CheckpointServiceImpl +import kotlin.jvm.optionals.getOrNull class JobServiceImpl internal constructor(private val clientOptions: ClientOptions) : JobService { @@ -66,6 +70,14 @@ class JobServiceImpl internal constructor(private val clientOptions: ClientOptio // get /fine_tuning/jobs/{fine_tuning_job_id}/events withRawResponse().listEvents(params, requestOptions).parse() + override fun pause(params: JobPauseParams, requestOptions: RequestOptions): FineTuningJob = + // post /fine_tuning/jobs/{fine_tuning_job_id}/pause + withRawResponse().pause(params, requestOptions).parse() + + override fun resume(params: JobResumeParams, requestOptions: RequestOptions): FineTuningJob = + // post /fine_tuning/jobs/{fine_tuning_job_id}/resume + withRawResponse().resume(params, requestOptions).parse() + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : JobService.WithRawResponse { @@ -111,6 +123,9 @@ class JobServiceImpl internal constructor(private val clientOptions: ClientOptio params: JobRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -171,6 +186,9 @@ class JobServiceImpl internal constructor(private val clientOptions: ClientOptio params: JobCancelParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -199,6 +217,9 @@ class JobServiceImpl internal constructor(private val clientOptions: ClientOptio params: JobListEventsParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -224,5 +245,65 @@ class JobServiceImpl internal constructor(private val clientOptions: ClientOptio } } } + + private val pauseHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + + override fun pause( + params: JobPauseParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "jobs", params._pathParam(0), "pause") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { pauseHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val resumeHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + + override fun resume( + params: JobResumeParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "jobs", params._pathParam(0), "resume") + .apply { params._body().ifPresent { body(json(clientOptions.jsonMapper, it)) } } + .build() + .prepare(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { resumeHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/MethodService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/MethodService.kt new file mode 100644 index 000000000..7d829c065 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/MethodService.kt @@ -0,0 +1,14 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning + +interface MethodService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** A view of [MethodService] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/MethodServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/MethodServiceImpl.kt new file mode 100644 index 000000000..a7750b2cf --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/MethodServiceImpl.kt @@ -0,0 +1,18 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning + +import com.openai.core.ClientOptions + +class MethodServiceImpl internal constructor(private val clientOptions: ClientOptions) : + MethodService { + + private val withRawResponse: MethodService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): MethodService.WithRawResponse = withRawResponse + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + MethodService.WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/alpha/GraderService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/alpha/GraderService.kt new file mode 100644 index 000000000..f6e4fe7ca --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/alpha/GraderService.kt @@ -0,0 +1,72 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning.alpha + +import com.google.errorprone.annotations.MustBeClosed +import com.openai.core.RequestOptions +import com.openai.core.http.HttpResponseFor +import com.openai.models.finetuning.alpha.graders.GraderRunParams +import com.openai.models.finetuning.alpha.graders.GraderRunResponse +import com.openai.models.finetuning.alpha.graders.GraderValidateParams +import com.openai.models.finetuning.alpha.graders.GraderValidateResponse + +interface GraderService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** Run a grader. */ + fun run(params: GraderRunParams): GraderRunResponse = run(params, RequestOptions.none()) + + /** @see [run] */ + fun run( + params: GraderRunParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): GraderRunResponse + + /** Validate a grader. */ + fun validate(params: GraderValidateParams): GraderValidateResponse = + validate(params, RequestOptions.none()) + + /** @see [validate] */ + fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): GraderValidateResponse + + /** A view of [GraderService] that provides access to raw HTTP responses for each method. */ + interface WithRawResponse { + + /** + * Returns a raw HTTP response for `post /fine_tuning/alpha/graders/run`, but is otherwise + * the same as [GraderService.run]. + */ + @MustBeClosed + fun run(params: GraderRunParams): HttpResponseFor = + run(params, RequestOptions.none()) + + /** @see [run] */ + @MustBeClosed + fun run( + params: GraderRunParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + + /** + * Returns a raw HTTP response for `post /fine_tuning/alpha/graders/validate`, but is + * otherwise the same as [GraderService.validate]. + */ + @MustBeClosed + fun validate(params: GraderValidateParams): HttpResponseFor = + validate(params, RequestOptions.none()) + + /** @see [validate] */ + @MustBeClosed + fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/alpha/GraderServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/alpha/GraderServiceImpl.kt new file mode 100644 index 000000000..4a9e21fc8 --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/alpha/GraderServiceImpl.kt @@ -0,0 +1,103 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning.alpha + +import com.openai.core.ClientOptions +import com.openai.core.RequestOptions +import com.openai.core.handlers.errorHandler +import com.openai.core.handlers.jsonHandler +import com.openai.core.handlers.withErrorHandler +import com.openai.core.http.HttpMethod +import com.openai.core.http.HttpRequest +import com.openai.core.http.HttpResponse.Handler +import com.openai.core.http.HttpResponseFor +import com.openai.core.http.json +import com.openai.core.http.parseable +import com.openai.core.prepare +import com.openai.models.ErrorObject +import com.openai.models.finetuning.alpha.graders.GraderRunParams +import com.openai.models.finetuning.alpha.graders.GraderRunResponse +import com.openai.models.finetuning.alpha.graders.GraderValidateParams +import com.openai.models.finetuning.alpha.graders.GraderValidateResponse + +class GraderServiceImpl internal constructor(private val clientOptions: ClientOptions) : + GraderService { + + private val withRawResponse: GraderService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): GraderService.WithRawResponse = withRawResponse + + override fun run(params: GraderRunParams, requestOptions: RequestOptions): GraderRunResponse = + // post /fine_tuning/alpha/graders/run + withRawResponse().run(params, requestOptions).parse() + + override fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions, + ): GraderValidateResponse = + // post /fine_tuning/alpha/graders/validate + withRawResponse().validate(params, requestOptions).parse() + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GraderService.WithRawResponse { + + private val errorHandler: Handler = errorHandler(clientOptions.jsonMapper) + + private val runHandler: Handler = + jsonHandler(clientOptions.jsonMapper).withErrorHandler(errorHandler) + + override fun run( + params: GraderRunParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "alpha", "graders", "run") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { runHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + + private val validateHandler: Handler = + jsonHandler(clientOptions.jsonMapper) + .withErrorHandler(errorHandler) + + override fun validate( + params: GraderValidateParams, + requestOptions: RequestOptions, + ): HttpResponseFor { + val request = + HttpRequest.builder() + .method(HttpMethod.POST) + .addPathSegments("fine_tuning", "alpha", "graders", "validate") + .body(json(clientOptions.jsonMapper, params._body())) + .build() + .prepare(clientOptions, params, deploymentModel = null) + val requestOptions = requestOptions.applyDefaults(RequestOptions.from(clientOptions)) + val response = clientOptions.httpClient.execute(request, requestOptions) + return response.parseable { + response + .use { validateHandler.handle(it) } + .also { + if (requestOptions.responseValidation!!) { + it.validate() + } + } + } + } + } +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionService.kt index 3271fff5d..547aa2659 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionService.kt @@ -25,6 +25,23 @@ interface PermissionService { * This enables organization owners to share fine-tuned models with other projects in their * organization. */ + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + ): PermissionCreatePage = create(fineTunedModelCheckpoint, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): PermissionCreatePage = + create( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [create] */ fun create(params: PermissionCreateParams): PermissionCreatePage = create(params, RequestOptions.none()) @@ -40,8 +57,26 @@ interface PermissionService { * Organization owners can use this endpoint to view all permissions for a fine-tuned model * checkpoint. */ - fun retrieve(params: PermissionRetrieveParams): PermissionRetrieveResponse = - retrieve(params, RequestOptions.none()) + fun retrieve(fineTunedModelCheckpoint: String): PermissionRetrieveResponse = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): PermissionRetrieveResponse = + retrieve( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [retrieve] */ + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + ): PermissionRetrieveResponse = + retrieve(fineTunedModelCheckpoint, params, RequestOptions.none()) /** @see [retrieve] */ fun retrieve( @@ -49,12 +84,35 @@ interface PermissionService { requestOptions: RequestOptions = RequestOptions.none(), ): PermissionRetrieveResponse + /** @see [retrieve] */ + fun retrieve(params: PermissionRetrieveParams): PermissionRetrieveResponse = + retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + fineTunedModelCheckpoint: String, + requestOptions: RequestOptions, + ): PermissionRetrieveResponse = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none(), requestOptions) + /** * **NOTE:** This endpoint requires an [admin API key](../admin-api-keys). * * Organization owners can use this endpoint to delete a permission for a fine-tuned model * checkpoint. */ + fun delete(permissionId: String, params: PermissionDeleteParams): PermissionDeleteResponse = + delete(permissionId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + permissionId: String, + params: PermissionDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): PermissionDeleteResponse = + delete(params.toBuilder().permissionId(permissionId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: PermissionDeleteParams): PermissionDeleteResponse = delete(params, RequestOptions.none()) @@ -73,6 +131,26 @@ interface PermissionService { * same as [PermissionService.create]. */ @MustBeClosed + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + ): HttpResponseFor = + create(fineTunedModelCheckpoint, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + fineTunedModelCheckpoint: String, + params: PermissionCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [create] */ + @MustBeClosed fun create(params: PermissionCreateParams): HttpResponseFor = create(params, RequestOptions.none()) @@ -90,8 +168,29 @@ interface PermissionService { */ @MustBeClosed fun retrieve( - params: PermissionRetrieveParams - ): HttpResponseFor = retrieve(params, RequestOptions.none()) + fineTunedModelCheckpoint: String + ): HttpResponseFor = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve( + params.toBuilder().fineTunedModelCheckpoint(fineTunedModelCheckpoint).build(), + requestOptions, + ) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTunedModelCheckpoint: String, + params: PermissionRetrieveParams = PermissionRetrieveParams.none(), + ): HttpResponseFor = + retrieve(fineTunedModelCheckpoint, params, RequestOptions.none()) /** @see [retrieve] */ @MustBeClosed @@ -100,12 +199,43 @@ interface PermissionService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + params: PermissionRetrieveParams + ): HttpResponseFor = retrieve(params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fineTunedModelCheckpoint: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + retrieve(fineTunedModelCheckpoint, PermissionRetrieveParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete * /fine_tuning/checkpoints/{fine_tuned_model_checkpoint}/permissions/{permission_id}`, but * is otherwise the same as [PermissionService.delete]. */ @MustBeClosed + fun delete( + permissionId: String, + params: PermissionDeleteParams, + ): HttpResponseFor = + delete(permissionId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + permissionId: String, + params: PermissionDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().permissionId(permissionId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete(params: PermissionDeleteParams): HttpResponseFor = delete(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionServiceImpl.kt index 7b8092686..6ac2f12e8 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/checkpoints/PermissionServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.finetuning.checkpoints import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -22,6 +23,7 @@ import com.openai.models.finetuning.checkpoints.permissions.PermissionDeletePara import com.openai.models.finetuning.checkpoints.permissions.PermissionDeleteResponse import com.openai.models.finetuning.checkpoints.permissions.PermissionRetrieveParams import com.openai.models.finetuning.checkpoints.permissions.PermissionRetrieveResponse +import kotlin.jvm.optionals.getOrNull class PermissionServiceImpl internal constructor(private val clientOptions: ClientOptions) : PermissionService { @@ -66,6 +68,9 @@ class PermissionServiceImpl internal constructor(private val clientOptions: Clie params: PermissionCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTunedModelCheckpoint", params.fineTunedModelCheckpoint().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -106,6 +111,9 @@ class PermissionServiceImpl internal constructor(private val clientOptions: Clie params: PermissionRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTunedModelCheckpoint", params.fineTunedModelCheckpoint().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -138,6 +146,9 @@ class PermissionServiceImpl internal constructor(private val clientOptions: Clie params: PermissionDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("permissionId", params.permissionId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointService.kt index 125b06c98..487177734 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointService.kt @@ -16,7 +16,22 @@ interface CheckpointService { fun withRawResponse(): WithRawResponse /** List checkpoints for a fine-tuning job. */ - fun list(params: CheckpointListParams): CheckpointListPage = list(params, RequestOptions.none()) + fun list(fineTuningJobId: String): CheckpointListPage = + list(fineTuningJobId, CheckpointListParams.none()) + + /** @see [list] */ + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): CheckpointListPage = + list(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [list] */ + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + ): CheckpointListPage = list(fineTuningJobId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -24,6 +39,13 @@ interface CheckpointService { requestOptions: RequestOptions = RequestOptions.none(), ): CheckpointListPage + /** @see [list] */ + fun list(params: CheckpointListParams): CheckpointListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(fineTuningJobId: String, requestOptions: RequestOptions): CheckpointListPage = + list(fineTuningJobId, CheckpointListParams.none(), requestOptions) + /** A view of [CheckpointService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -32,8 +54,25 @@ interface CheckpointService { * but is otherwise the same as [CheckpointService.list]. */ @MustBeClosed - fun list(params: CheckpointListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(fineTuningJobId: String): HttpResponseFor = + list(fineTuningJobId, CheckpointListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().fineTuningJobId(fineTuningJobId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + fineTuningJobId: String, + params: CheckpointListParams = CheckpointListParams.none(), + ): HttpResponseFor = + list(fineTuningJobId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -41,5 +80,18 @@ interface CheckpointService { params: CheckpointListParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [list] */ + @MustBeClosed + fun list(params: CheckpointListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + fineTuningJobId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + list(fineTuningJobId, CheckpointListParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceImpl.kt index 34d91dc8c..23fe2d2d2 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.finetuning.jobs import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -17,6 +18,7 @@ import com.openai.models.ErrorObject import com.openai.models.finetuning.jobs.checkpoints.CheckpointListPage import com.openai.models.finetuning.jobs.checkpoints.CheckpointListPageResponse import com.openai.models.finetuning.jobs.checkpoints.CheckpointListParams +import kotlin.jvm.optionals.getOrNull class CheckpointServiceImpl internal constructor(private val clientOptions: ClientOptions) : CheckpointService { @@ -47,6 +49,9 @@ class CheckpointServiceImpl internal constructor(private val clientOptions: Clie params: CheckpointListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fineTuningJobId", params.fineTuningJobId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/graders/GraderModelService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/graders/GraderModelService.kt new file mode 100644 index 000000000..40f334c4c --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/graders/GraderModelService.kt @@ -0,0 +1,16 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.graders + +interface GraderModelService { + + /** + * Returns a view of this service that provides access to raw HTTP responses for each method. + */ + fun withRawResponse(): WithRawResponse + + /** + * A view of [GraderModelService] that provides access to raw HTTP responses for each method. + */ + interface WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/graders/GraderModelServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/graders/GraderModelServiceImpl.kt new file mode 100644 index 000000000..01f3f0d1a --- /dev/null +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/graders/GraderModelServiceImpl.kt @@ -0,0 +1,18 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.graders + +import com.openai.core.ClientOptions + +class GraderModelServiceImpl internal constructor(private val clientOptions: ClientOptions) : + GraderModelService { + + private val withRawResponse: GraderModelService.WithRawResponse by lazy { + WithRawResponseImpl(clientOptions) + } + + override fun withRawResponse(): GraderModelService.WithRawResponse = withRawResponse + + class WithRawResponseImpl internal constructor(private val clientOptions: ClientOptions) : + GraderModelService.WithRawResponse +} diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemService.kt index bbfab36ef..81690e164 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemService.kt @@ -16,7 +16,20 @@ interface InputItemService { fun withRawResponse(): WithRawResponse /** Returns a list of input items for a given response. */ - fun list(params: InputItemListParams): InputItemListPage = list(params, RequestOptions.none()) + fun list(responseId: String): InputItemListPage = list(responseId, InputItemListParams.none()) + + /** @see [list] */ + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): InputItemListPage = list(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [list] */ + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + ): InputItemListPage = list(responseId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -24,6 +37,13 @@ interface InputItemService { requestOptions: RequestOptions = RequestOptions.none(), ): InputItemListPage + /** @see [list] */ + fun list(params: InputItemListParams): InputItemListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(responseId: String, requestOptions: RequestOptions): InputItemListPage = + list(responseId, InputItemListParams.none(), requestOptions) + /** A view of [InputItemService] that provides access to raw HTTP responses for each method. */ interface WithRawResponse { @@ -32,8 +52,24 @@ interface InputItemService { * otherwise the same as [InputItemService.list]. */ @MustBeClosed - fun list(params: InputItemListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(responseId: String): HttpResponseFor = + list(responseId, InputItemListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().responseId(responseId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + responseId: String, + params: InputItemListParams = InputItemListParams.none(), + ): HttpResponseFor = list(responseId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -41,5 +77,18 @@ interface InputItemService { params: InputItemListParams, requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + + /** @see [list] */ + @MustBeClosed + fun list(params: InputItemListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + responseId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + list(responseId, InputItemListParams.none(), requestOptions) } } diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemServiceImpl.kt index 19e1a397f..aa535bbc7 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/responses/InputItemServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.responses import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -17,6 +18,7 @@ import com.openai.models.ErrorObject import com.openai.models.responses.inputitems.InputItemListPage import com.openai.models.responses.inputitems.InputItemListParams import com.openai.models.responses.inputitems.ResponseItemList +import kotlin.jvm.optionals.getOrNull class InputItemServiceImpl internal constructor(private val clientOptions: ClientOptions) : InputItemService { @@ -46,6 +48,9 @@ class InputItemServiceImpl internal constructor(private val clientOptions: Clien params: InputItemListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("responseId", params.responseId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartService.kt index 1c157e709..a19904934 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartService.kt @@ -27,6 +27,17 @@ interface PartService { * Parts when you * [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete). */ + fun create(uploadId: String, params: PartCreateParams): UploadPart = + create(uploadId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + uploadId: String, + params: PartCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): UploadPart = create(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [create] */ fun create(params: PartCreateParams): UploadPart = create(params, RequestOptions.none()) /** @see [create] */ @@ -43,6 +54,20 @@ interface PartService { * same as [PartService.create]. */ @MustBeClosed + fun create(uploadId: String, params: PartCreateParams): HttpResponseFor = + create(uploadId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + uploadId: String, + params: PartCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create(params.toBuilder().uploadId(uploadId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: PartCreateParams): HttpResponseFor = create(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartServiceImpl.kt index 0f616b5db..23bf0b689 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/uploads/PartServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.uploads import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -17,6 +18,7 @@ import com.openai.core.prepare import com.openai.models.ErrorObject import com.openai.models.uploads.parts.PartCreateParams import com.openai.models.uploads.parts.UploadPart +import kotlin.jvm.optionals.getOrNull class PartServiceImpl internal constructor(private val clientOptions: ClientOptions) : PartService { @@ -42,6 +44,9 @@ class PartServiceImpl internal constructor(private val clientOptions: ClientOpti params: PartCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("uploadId", params.uploadId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchService.kt index 5bf2fe582..2f9f55f5c 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchService.kt @@ -20,6 +20,18 @@ interface FileBatchService { fun withRawResponse(): WithRawResponse /** Create a vector store file batch. */ + fun create(vectorStoreId: String, params: FileBatchCreateParams): VectorStoreFileBatch = + create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFileBatch = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ fun create(params: FileBatchCreateParams): VectorStoreFileBatch = create(params, RequestOptions.none()) @@ -30,6 +42,17 @@ interface FileBatchService { ): VectorStoreFileBatch /** Retrieves a vector store file batch. */ + fun retrieve(batchId: String, params: FileBatchRetrieveParams): VectorStoreFileBatch = + retrieve(batchId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFileBatch = retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: FileBatchRetrieveParams): VectorStoreFileBatch = retrieve(params, RequestOptions.none()) @@ -43,6 +66,17 @@ interface FileBatchService { * Cancel a vector store file batch. This attempts to cancel the processing of files in this * batch as soon as possible. */ + fun cancel(batchId: String, params: FileBatchCancelParams): VectorStoreFileBatch = + cancel(batchId, params, RequestOptions.none()) + + /** @see [cancel] */ + fun cancel( + batchId: String, + params: FileBatchCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFileBatch = cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ fun cancel(params: FileBatchCancelParams): VectorStoreFileBatch = cancel(params, RequestOptions.none()) @@ -53,6 +87,18 @@ interface FileBatchService { ): VectorStoreFileBatch /** Returns a list of vector store files in a batch. */ + fun listFiles(batchId: String, params: FileBatchListFilesParams): FileBatchListFilesPage = + listFiles(batchId, params, RequestOptions.none()) + + /** @see [listFiles] */ + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FileBatchListFilesPage = + listFiles(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [listFiles] */ fun listFiles(params: FileBatchListFilesParams): FileBatchListFilesPage = listFiles(params, RequestOptions.none()) @@ -70,6 +116,23 @@ interface FileBatchService { * is otherwise the same as [FileBatchService.create]. */ @MustBeClosed + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + ): HttpResponseFor = + create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + vectorStoreId: String, + params: FileBatchCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: FileBatchCreateParams): HttpResponseFor = create(params, RequestOptions.none()) @@ -86,6 +149,22 @@ interface FileBatchService { * [FileBatchService.retrieve]. */ @MustBeClosed + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + ): HttpResponseFor = retrieve(batchId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + batchId: String, + params: FileBatchRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: FileBatchRetrieveParams): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -102,6 +181,22 @@ interface FileBatchService { * same as [FileBatchService.cancel]. */ @MustBeClosed + fun cancel( + batchId: String, + params: FileBatchCancelParams, + ): HttpResponseFor = cancel(batchId, params, RequestOptions.none()) + + /** @see [cancel] */ + @MustBeClosed + fun cancel( + batchId: String, + params: FileBatchCancelParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + cancel(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [cancel] */ + @MustBeClosed fun cancel(params: FileBatchCancelParams): HttpResponseFor = cancel(params, RequestOptions.none()) @@ -118,6 +213,23 @@ interface FileBatchService { * same as [FileBatchService.listFiles]. */ @MustBeClosed + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + ): HttpResponseFor = + listFiles(batchId, params, RequestOptions.none()) + + /** @see [listFiles] */ + @MustBeClosed + fun listFiles( + batchId: String, + params: FileBatchListFilesParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + listFiles(params.toBuilder().batchId(batchId).build(), requestOptions) + + /** @see [listFiles] */ + @MustBeClosed fun listFiles(params: FileBatchListFilesParams): HttpResponseFor = listFiles(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchServiceImpl.kt index 516848c43..edfa1dd21 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileBatchServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.vectorstores import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -23,6 +24,7 @@ import com.openai.models.vectorstores.filebatches.FileBatchListFilesPageResponse import com.openai.models.vectorstores.filebatches.FileBatchListFilesParams import com.openai.models.vectorstores.filebatches.FileBatchRetrieveParams import com.openai.models.vectorstores.filebatches.VectorStoreFileBatch +import kotlin.jvm.optionals.getOrNull class FileBatchServiceImpl internal constructor(private val clientOptions: ClientOptions) : FileBatchService { @@ -79,6 +81,9 @@ class FileBatchServiceImpl internal constructor(private val clientOptions: Clien params: FileBatchCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -108,6 +113,9 @@ class FileBatchServiceImpl internal constructor(private val clientOptions: Clien params: FileBatchRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -141,6 +149,9 @@ class FileBatchServiceImpl internal constructor(private val clientOptions: Clien params: FileBatchCancelParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -176,6 +187,9 @@ class FileBatchServiceImpl internal constructor(private val clientOptions: Clien params: FileBatchListFilesParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("batchId", params.batchId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileService.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileService.kt index 1d081a12c..9cb49b698 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileService.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileService.kt @@ -28,6 +28,18 @@ interface FileService { * [File](https://platform.openai.com/docs/api-reference/files) to a * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). */ + fun create(vectorStoreId: String, params: FileCreateParams): VectorStoreFile = + create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + fun create( + vectorStoreId: String, + params: FileCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFile = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ fun create(params: FileCreateParams): VectorStoreFile = create(params, RequestOptions.none()) /** @see [create] */ @@ -37,6 +49,17 @@ interface FileService { ): VectorStoreFile /** Retrieves a vector store file. */ + fun retrieve(fileId: String, params: FileRetrieveParams): VectorStoreFile = + retrieve(fileId, params, RequestOptions.none()) + + /** @see [retrieve] */ + fun retrieve( + fileId: String, + params: FileRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFile = retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ fun retrieve(params: FileRetrieveParams): VectorStoreFile = retrieve(params, RequestOptions.none()) @@ -47,6 +70,17 @@ interface FileService { ): VectorStoreFile /** Update attributes on a vector store file. */ + fun update(fileId: String, params: FileUpdateParams): VectorStoreFile = + update(fileId, params, RequestOptions.none()) + + /** @see [update] */ + fun update( + fileId: String, + params: FileUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFile = update(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [update] */ fun update(params: FileUpdateParams): VectorStoreFile = update(params, RequestOptions.none()) /** @see [update] */ @@ -56,7 +90,18 @@ interface FileService { ): VectorStoreFile /** Returns a list of vector store files. */ - fun list(params: FileListParams): FileListPage = list(params, RequestOptions.none()) + fun list(vectorStoreId: String): FileListPage = list(vectorStoreId, FileListParams.none()) + + /** @see [list] */ + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): FileListPage = list(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [list] */ + fun list(vectorStoreId: String, params: FileListParams = FileListParams.none()): FileListPage = + list(vectorStoreId, params, RequestOptions.none()) /** @see [list] */ fun list( @@ -64,11 +109,29 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): FileListPage + /** @see [list] */ + fun list(params: FileListParams): FileListPage = list(params, RequestOptions.none()) + + /** @see [list] */ + fun list(vectorStoreId: String, requestOptions: RequestOptions): FileListPage = + list(vectorStoreId, FileListParams.none(), requestOptions) + /** * Delete a vector store file. This will remove the file from the vector store but the file * itself will not be deleted. To delete the file, use the * [delete file](https://platform.openai.com/docs/api-reference/files/delete) endpoint. */ + fun delete(fileId: String, params: FileDeleteParams): VectorStoreFileDeleted = + delete(fileId, params, RequestOptions.none()) + + /** @see [delete] */ + fun delete( + fileId: String, + params: FileDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): VectorStoreFileDeleted = delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ fun delete(params: FileDeleteParams): VectorStoreFileDeleted = delete(params, RequestOptions.none()) @@ -79,6 +142,17 @@ interface FileService { ): VectorStoreFileDeleted /** Retrieve the parsed contents of a vector store file. */ + fun content(fileId: String, params: FileContentParams): FileContentPage = + content(fileId, params, RequestOptions.none()) + + /** @see [content] */ + fun content( + fileId: String, + params: FileContentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): FileContentPage = content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ fun content(params: FileContentParams): FileContentPage = content(params, RequestOptions.none()) /** @see [content] */ @@ -95,6 +169,22 @@ interface FileService { * otherwise the same as [FileService.create]. */ @MustBeClosed + fun create( + vectorStoreId: String, + params: FileCreateParams, + ): HttpResponseFor = create(vectorStoreId, params, RequestOptions.none()) + + /** @see [create] */ + @MustBeClosed + fun create( + vectorStoreId: String, + params: FileCreateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + create(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [create] */ + @MustBeClosed fun create(params: FileCreateParams): HttpResponseFor = create(params, RequestOptions.none()) @@ -110,6 +200,20 @@ interface FileService { * but is otherwise the same as [FileService.retrieve]. */ @MustBeClosed + fun retrieve(fileId: String, params: FileRetrieveParams): HttpResponseFor = + retrieve(fileId, params, RequestOptions.none()) + + /** @see [retrieve] */ + @MustBeClosed + fun retrieve( + fileId: String, + params: FileRetrieveParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + retrieve(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [retrieve] */ + @MustBeClosed fun retrieve(params: FileRetrieveParams): HttpResponseFor = retrieve(params, RequestOptions.none()) @@ -125,6 +229,20 @@ interface FileService { * but is otherwise the same as [FileService.update]. */ @MustBeClosed + fun update(fileId: String, params: FileUpdateParams): HttpResponseFor = + update(fileId, params, RequestOptions.none()) + + /** @see [update] */ + @MustBeClosed + fun update( + fileId: String, + params: FileUpdateParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + update(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [update] */ + @MustBeClosed fun update(params: FileUpdateParams): HttpResponseFor = update(params, RequestOptions.none()) @@ -140,8 +258,24 @@ interface FileService { * otherwise the same as [FileService.list]. */ @MustBeClosed - fun list(params: FileListParams): HttpResponseFor = - list(params, RequestOptions.none()) + fun list(vectorStoreId: String): HttpResponseFor = + list(vectorStoreId, FileListParams.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + list(params.toBuilder().vectorStoreId(vectorStoreId).build(), requestOptions) + + /** @see [list] */ + @MustBeClosed + fun list( + vectorStoreId: String, + params: FileListParams = FileListParams.none(), + ): HttpResponseFor = list(vectorStoreId, params, RequestOptions.none()) /** @see [list] */ @MustBeClosed @@ -150,12 +284,41 @@ interface FileService { requestOptions: RequestOptions = RequestOptions.none(), ): HttpResponseFor + /** @see [list] */ + @MustBeClosed + fun list(params: FileListParams): HttpResponseFor = + list(params, RequestOptions.none()) + + /** @see [list] */ + @MustBeClosed + fun list( + vectorStoreId: String, + requestOptions: RequestOptions, + ): HttpResponseFor = + list(vectorStoreId, FileListParams.none(), requestOptions) + /** * Returns a raw HTTP response for `delete * /vector_stores/{vector_store_id}/files/{file_id}`, but is otherwise the same as * [FileService.delete]. */ @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams, + ): HttpResponseFor = delete(fileId, params, RequestOptions.none()) + + /** @see [delete] */ + @MustBeClosed + fun delete( + fileId: String, + params: FileDeleteParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + delete(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [delete] */ + @MustBeClosed fun delete(params: FileDeleteParams): HttpResponseFor = delete(params, RequestOptions.none()) @@ -172,6 +335,20 @@ interface FileService { * [FileService.content]. */ @MustBeClosed + fun content(fileId: String, params: FileContentParams): HttpResponseFor = + content(fileId, params, RequestOptions.none()) + + /** @see [content] */ + @MustBeClosed + fun content( + fileId: String, + params: FileContentParams, + requestOptions: RequestOptions = RequestOptions.none(), + ): HttpResponseFor = + content(params.toBuilder().fileId(fileId).build(), requestOptions) + + /** @see [content] */ + @MustBeClosed fun content(params: FileContentParams): HttpResponseFor = content(params, RequestOptions.none()) diff --git a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileServiceImpl.kt b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileServiceImpl.kt index c3e9174af..971cf72ed 100644 --- a/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileServiceImpl.kt +++ b/openai-java-core/src/main/kotlin/com/openai/services/blocking/vectorstores/FileServiceImpl.kt @@ -4,6 +4,7 @@ package com.openai.services.blocking.vectorstores import com.openai.core.ClientOptions import com.openai.core.RequestOptions +import com.openai.core.checkRequired import com.openai.core.handlers.errorHandler import com.openai.core.handlers.jsonHandler import com.openai.core.handlers.withErrorHandler @@ -28,6 +29,7 @@ import com.openai.models.vectorstores.files.FileRetrieveParams import com.openai.models.vectorstores.files.FileUpdateParams import com.openai.models.vectorstores.files.VectorStoreFile import com.openai.models.vectorstores.files.VectorStoreFileDeleted +import kotlin.jvm.optionals.getOrNull class FileServiceImpl internal constructor(private val clientOptions: ClientOptions) : FileService { @@ -87,6 +89,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileCreateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -115,6 +120,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileRetrieveParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -147,6 +155,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileUpdateParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.POST) @@ -181,6 +192,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileListParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("vectorStoreId", params.vectorStoreId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) @@ -216,6 +230,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileDeleteParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.DELETE) @@ -250,6 +267,9 @@ class FileServiceImpl internal constructor(private val clientOptions: ClientOpti params: FileContentParams, requestOptions: RequestOptions, ): HttpResponseFor { + // We check here instead of in the params builder because this can be specified + // positionally or in the params class. + checkRequired("fileId", params.fileId().getOrNull()) val request = HttpRequest.builder() .method(HttpMethod.GET) diff --git a/openai-java-core/src/test/kotlin/com/openai/core/AutoPagerAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/core/AutoPagerAsyncTest.kt new file mode 100644 index 000000000..e9e9137e6 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/core/AutoPagerAsyncTest.kt @@ -0,0 +1,182 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.core + +import com.openai.core.http.AsyncStreamResponse +import java.util.Optional +import java.util.concurrent.CompletableFuture +import java.util.concurrent.Executor +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.catchThrowable +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.junit.jupiter.MockitoExtension +import org.mockito.kotlin.any +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.doAnswer +import org.mockito.kotlin.inOrder +import org.mockito.kotlin.mock +import org.mockito.kotlin.never +import org.mockito.kotlin.spy +import org.mockito.kotlin.times +import org.mockito.kotlin.verify +import org.mockito.kotlin.whenever + +@ExtendWith(MockitoExtension::class) +internal class AutoPagerAsyncTest { + + companion object { + + private val ERROR = RuntimeException("ERROR!") + } + + private class PageAsyncImpl( + private val items: List, + private val hasNext: Boolean = true, + ) : PageAsync { + + val nextPageFuture: CompletableFuture> = CompletableFuture() + + override fun hasNextPage(): Boolean = hasNext + + override fun nextPage(): CompletableFuture> = nextPageFuture + + override fun items(): List = items + } + + private val executor = + spy { + doAnswer { invocation -> invocation.getArgument(0).run() } + .whenever(it) + .execute(any()) + } + private val handler = mock>() + + @Test + fun subscribe_whenAlreadySubscribed_throws() { + val autoPagerAsync = AutoPagerAsync.from(PageAsyncImpl(emptyList()), executor) + autoPagerAsync.subscribe {} + clearInvocations(executor) + + val throwable = catchThrowable { autoPagerAsync.subscribe {} } + + assertThat(throwable).isInstanceOf(IllegalStateException::class.java) + assertThat(throwable).hasMessage("Cannot subscribe more than once") + verify(executor, never()).execute(any()) + } + + @Test + fun subscribe_whenClosed_throws() { + val autoPagerAsync = AutoPagerAsync.from(PageAsyncImpl(emptyList()), executor) + autoPagerAsync.close() + + val throwable = catchThrowable { autoPagerAsync.subscribe {} } + + assertThat(throwable).isInstanceOf(IllegalStateException::class.java) + assertThat(throwable).hasMessage("Cannot subscribe after the response is closed") + verify(executor, never()).execute(any()) + } + + @Test + fun subscribe_whenFirstPageNonEmpty_runsHandler() { + val page = PageAsyncImpl(listOf("item1", "item2", "item3"), hasNext = false) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + + autoPagerAsync.subscribe(handler) + + inOrder(executor, handler) { + verify(executor, times(1)).execute(any()) + verify(handler, times(1)).onNext("item1") + verify(handler, times(1)).onNext("item2") + verify(handler, times(1)).onNext("item3") + verify(handler, times(1)).onComplete(Optional.empty()) + } + } + + @Test + fun subscribe_whenFutureCompletesAfterClose_doesNothing() { + val page = PageAsyncImpl(listOf("page1")) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + autoPagerAsync.subscribe(handler) + autoPagerAsync.close() + + page.nextPageFuture.complete(PageAsyncImpl(listOf("page2"))) + + verify(handler, times(1)).onNext("page1") + verify(handler, never()).onNext("page2") + verify(handler, times(1)).onComplete(Optional.empty()) + verify(executor, times(1)).execute(any()) + } + + @Test + fun subscribe_whenFutureErrors_callsOnComplete() { + val page = PageAsyncImpl(emptyList()) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + autoPagerAsync.subscribe(handler) + + page.nextPageFuture.completeExceptionally(ERROR) + + verify(executor, times(1)).execute(any()) + verify(handler, never()).onNext(any()) + verify(handler, times(1)).onComplete(Optional.of(ERROR)) + } + + @Test + fun subscribe_whenFutureCompletes_runsHandler() { + val page = PageAsyncImpl(listOf("chunk1", "chunk2")) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + + autoPagerAsync.subscribe(handler) + + verify(handler, never()).onComplete(any()) + inOrder(executor, handler) { + verify(executor, times(1)).execute(any()) + verify(handler, times(1)).onNext("chunk1") + verify(handler, times(1)).onNext("chunk2") + } + clearInvocations(executor, handler) + + page.nextPageFuture.complete(PageAsyncImpl(listOf("chunk3", "chunk4"), hasNext = false)) + + verify(executor, never()).execute(any()) + inOrder(handler) { + verify(handler, times(1)).onNext("chunk3") + verify(handler, times(1)).onNext("chunk4") + verify(handler, times(1)).onComplete(Optional.empty()) + } + } + + @Test + fun onCompleteFuture_whenNextPageFutureNotCompleted_onCompleteFutureNotCompleted() { + val page = PageAsyncImpl(listOf("chunk1", "chunk2")) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + autoPagerAsync.subscribe {} + + val onCompletableFuture = autoPagerAsync.onCompleteFuture() + + assertThat(onCompletableFuture).isNotCompleted + } + + @Test + fun onCompleteFuture_whenNextPageFutureErrors_onCompleteFutureCompletedExceptionally() { + val page = PageAsyncImpl(listOf("chunk1", "chunk2")) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + autoPagerAsync.subscribe {} + page.nextPageFuture.completeExceptionally(ERROR) + + val onCompletableFuture = autoPagerAsync.onCompleteFuture() + + assertThat(onCompletableFuture).isCompletedExceptionally + } + + @Test + fun onCompleteFuture_whenNoNextPage_onCompleteFutureCompleted() { + val page = PageAsyncImpl(listOf("chunk1", "chunk2"), hasNext = false) + val autoPagerAsync = AutoPagerAsync.from(page, executor) + autoPagerAsync.subscribe {} + + val onCompletableFuture = autoPagerAsync.onCompleteFuture() + + assertThat(onCompletableFuture).isCompleted + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/core/AutoPagerTest.kt b/openai-java-core/src/test/kotlin/com/openai/core/AutoPagerTest.kt new file mode 100644 index 000000000..17e586320 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/core/AutoPagerTest.kt @@ -0,0 +1,41 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.core + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class AutoPagerTest { + + private class PageImpl( + private val items: List, + private val nextPage: Page? = null, + ) : Page { + + override fun hasNextPage(): Boolean = nextPage != null + + override fun nextPage(): Page = nextPage!! + + override fun items(): List = items + } + + @Test + fun iterator() { + val firstPage = + PageImpl(listOf("chunk1", "chunk2"), nextPage = PageImpl(listOf("chunk3", "chunk4"))) + + val autoPager = AutoPager.from(firstPage) + + assertThat(autoPager).containsExactly("chunk1", "chunk2", "chunk3", "chunk4") + } + + @Test + fun stream() { + val firstPage = + PageImpl(listOf("chunk1", "chunk2"), nextPage = PageImpl(listOf("chunk3", "chunk4"))) + + val autoPager = AutoPager.from(firstPage) + + assertThat(autoPager.stream()).containsExactly("chunk1", "chunk2", "chunk3", "chunk4") + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTest.kt b/openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTest.kt new file mode 100644 index 000000000..dd5cdd572 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTest.kt @@ -0,0 +1,1520 @@ +package com.openai.core + +import com.fasterxml.jackson.annotation.JsonClassDescription +import com.fasterxml.jackson.annotation.JsonIgnore +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.annotation.JsonPropertyDescription +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.node.ObjectNode +import com.openai.errors.OpenAIInvalidDataException +import java.util.Optional +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatNoException +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.AfterTestExecutionCallback +import org.junit.jupiter.api.extension.ExtensionContext +import org.junit.jupiter.api.extension.RegisterExtension + +/** Tests for the `StructuredOutputs` functions and the [JsonSchemaValidator]. */ +internal class StructuredOutputsTest { + companion object { + private const val SCHEMA = "\$schema" + private const val SCHEMA_VER = "https://json-schema.org/draft/2020-12/schema" + private const val DEFS = "\$defs" + private const val REF = "\$ref" + + /** + * `true` to print the schema and validation errors for all executed tests, or `false` to + * print them only for failed tests. + */ + private const val VERBOSE_MODE = false + + private fun parseJson(schemaString: String) = ObjectMapper().readTree(schemaString) + } + + /** + * A validator that can be used by each unit test. A new validation instance is created for each + * test, as each test is run from its own instance of the test class. If a test fails, any + * validation errors are automatically printed to standard output to aid diagnosis. + */ + val validator = JsonSchemaValidator.create() + + /** + * The schema that was created by the unit test. This may be printed out after a test fails to + * aid in diagnosing the cause of the failure. In that case, this property must be set, or an + * error will occur. However, it will only be printed if the failed test method has the name + * prefix `schemaTest_`, so only test methods with that naming pattern need to set this field. + */ + lateinit var schema: JsonNode + + /** + * An extension to JUnit that prints the [schema] and the validation status (including any + * errors) when a test fails. This applies only to test methods whose names are prefixed with + * `schemaTest_`. An error will occur if [schema] was not set, but this can be avoided by only + * using the method name prefix for test methods that set [schema]. This reporting is intended + * as an aid to diagnosing test failures. + */ + @Suppress("unused") + @RegisterExtension + val printValidationErrorsOnFailure: AfterTestExecutionCallback = + object : AfterTestExecutionCallback { + @Throws(Exception::class) + override fun afterTestExecution(context: ExtensionContext) { + if ( + context.displayName.startsWith("schemaTest_") && + (VERBOSE_MODE || context.executionException.isPresent) + ) { + // Test failed. + println("Schema: ${schema.toPrettyString()}\n") + println("$validator\n") + } + } + } + + // NOTE: In most of these tests, it is assumed that the schema is generated as expected; it is + // not examined in fine detail if the validator succeeds or fails with the expected errors. + + @Test + fun schemaTest_minimalSchema() { + class X() + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_minimalListSchema() { + val s: List = listOf() + + schema = extractSchema(s.javaClass) + validator.validate(schema) + + // Currently, the generated schema looks like this: + // + // { + // "$schema" : "https://json-schema.org/draft/2020-12/schema", + // "type" : "array", + // "items" : { } + // } + // + // That causes an error, as the `"items"` object is empty when it should be a valid + // sub-schema. Something like this is what would be valid: + // + // { + // "$schema" : "https://json-schema.org/draft/2020-12/schema", + // "type" : "array", + // "items" : { + // "type" : "string" + // } + // } + // + // The reason for the failure is that generic type information is erased for scopes like + // local variables, but generic type information for fields is retained as part of the class + // metadata. This is the expected behavior in Java, so this test expects an invalid schema. + assertThat(validator.isValid()).isFalse + assertThat(validator.errors()).hasSize(2) + assertThat(validator.errors()[0]).isEqualTo("#/items: Schema or sub-schema is empty.") + assertThat(validator.errors()[1]) + .isEqualTo("#/items: Expected exactly one of 'type' or 'anyOf' or '$REF'.") + } + + @Test + fun schemaTest_listFieldSchema() { + @Suppress("unused") class X(val s: List) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + // This gives a root schema with `"type" : "string"` and `"const" : "HELLO"` + // Unfortunately, an "enum class" cannot be defined within a function or within a class within + // a function. + @Suppress("unused") + enum class MinimalEnum1 { + HELLO + } + + @Test + fun schemaTest_minimalEnumSchema1() { + schema = extractSchema(MinimalEnum1::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + // This gives a root schema with `"type" : "string"` and `"enum" : [ "HELLO", "WORLD" ]` + @Suppress("unused") + enum class MinimalEnum2 { + HELLO, + WORLD, + } + + @Test + fun schemaTest_minimalEnumSchema2() { + schema = extractSchema(MinimalEnum2::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_nonStringEnum() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "integer", + "enum" : [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_tinySchema() { + @Suppress("unused") class X(val s: String) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_tinySchemaFromOptionalString() { + // Using an `Optional` will result in this JSON: `"type" : [ "string", "null" ]`. + // That is supported by the OpenAI Structured Outputs API spec, as long as the field is also + // marked as required. Though required, it is still allowed for the field to be explicitly + // set to `"null"`. + @Suppress("unused") class X(val s: Optional) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_tinySchemaFromOptionalBoolean() { + @Suppress("unused") class X(val b: Optional) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_tinySchemaFromOptionalInteger() { + @Suppress("unused") class X(val i: Optional) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_tinySchemaFromOptionalNumber() { + @Suppress("unused") class X(val n: Optional) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_arraySchemaFromOptional() { + @Suppress("unused") class X(val s: Optional>) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_arrayTypeMissingItems() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "array" + } + """ + ) + validator.validate(schema) + + // Check once here that "validator.isValid()" returns "false" when there is an error. In + // the other tests, there is no need to repeat this assertion, as it would be redundant. + assertThat(validator.isValid()).isFalse + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'items' field is missing or is not an object.") + } + + @Test + fun schemaTest_arrayTypeWithWrongItemsType() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "array", + "items" : [ "should_not_be_an_array" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'items' field is missing or is not an object.") + } + + @Test + @Suppress("unused") + fun schemaTest_objectSubSchemaFromOptional() { + class X(val s: Optional) + class Y(val x: Optional) + + schema = extractSchema(Y::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_badOptionalTypeNotArray() { + // Testing more for code coverage than for anything expected to go wrong in practice. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : { "type" : "string" } + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'type' field is not a type name or array of type names.") + } + + @Test + fun schemaTest_badOptionalTypeNoNull1() { + // Testing more for code coverage than for anything expected to go wrong in practice. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "string" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/type: Expected exactly two types, both strings.") + } + + @Test + fun schemaTest_badOptionalTypeNoNull2() { + // If "type" is an array, one of the two "type" values must be "null". + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "string", "number" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/type: Expected one type name and one \"null\".") + } + + @Test + fun schemaTest_badOptionalTypeNoNull3() { + // If "type" is an array, there must be two type values only, one of them "null". + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "string", "number", "null" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/type: Expected exactly two types, both strings.") + } + + @Test + fun schemaTest_badOptionalTypeNoStringTypeNames() { + // If "type" is an array, there must be two type values only, one of them "null". + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "string", null ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/type: Expected exactly two types, both strings.") + } + + @Test + fun schemaTest_badOptionalTypeAllNull() { + // If "type" is an array, there must be two type values only, and only one of them "null". + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "null", "null" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/type: Expected one type name and one \"null\".") + } + + @Test + fun schemaTest_badOptionalTypeUnknown() { + // If "type" is an array, there must be two type values only, and only one of them "null". + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "unknown", "null" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]).isEqualTo("#/type: Unsupported 'type' value: 'unknown'.") + } + + @Test + fun schemaTest_goodOptionalTypeNullFirst() { + // The validator should be lenient about the order of the null/not-null types in the array. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : [ "null", "string" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_tinyRecursiveSchema() { + @Suppress("unused") class X(val s: String, val x: X?) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_unsupportedKeywords() { + // OpenAI lists a set of keywords that are not allowed, but the set is not exhaustive. Check + // that everything named in that set is identified as not allowed, as that is the minimum + // level of validation expected. Check at the root schema and a sub-schema. There is no need + // to match the keywords to their expected schema types or be concerned about the values of + // the keyword fields, which makes testing easier. + val keywordsNotAllowed = + listOf( + "minLength", + "maxLength", + "pattern", + "format", + "minimum", + "maximum", + "multipleOf", + "patternProperties", + "unevaluatedProperties", + "propertyNames", + "minProperties", + "maxProperties", + "unevaluatedItems", + "contains", + "minContains", + "maxContains", + "minItems", + "maxItems", + "uniqueItems", + ) + val notAllowedUses = keywordsNotAllowed.joinToString(", ") { "\"$it\" : \"\"" } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "x" : { + "type" : "string", + $notAllowedUses + } + }, + $notAllowedUses, + "additionalProperties" : false, + "required" : [ "x" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(keywordsNotAllowed.size * 2) + keywordsNotAllowed.forEachIndexed { index, keyword -> + assertThat(validator.errors()[index]) + .isEqualTo("#: Use of '$keyword' is not supported here.") + assertThat(validator.errors()[index + keywordsNotAllowed.size]) + .isEqualTo("#/properties/x: Use of '$keyword' is not supported here.") + } + } + + @Test + fun schemaTest_propertyNotMarkedRequired() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "additionalProperties" : false, + "required" : [ ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/required: 'properties' field 'name' is not listed as 'required'.") + } + + @Test + fun schemaTest_requiredArrayNull() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "additionalProperties" : false, + "required" : null + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/required: 'properties' field 'name' is not listed as 'required'.") + } + + @Test + fun schemaTest_requiredArrayMissing() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/required: 'properties' field 'name' is not listed as 'required'.") + } + + @Test + fun schemaTest_additionalPropertiesMissing() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "required" : [ "name" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'additionalProperties' field is missing or is not set to 'false'.") + } + + @Test + fun schemaTest_additionalPropertiesTrue() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "additionalProperties" : true, + "required" : [ "name" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'additionalProperties' field is missing or is not set to 'false'.") + } + + @Test + fun schemaTest_objectPropertiesMissing() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "additionalProperties" : false, + "required" : [ ] + } + """ + ) + validator.validate(schema) + + // For now, allow that an object may have no properties. Update this if that is revised. + assertThat(validator.isValid()).isTrue() + } + + @Test + fun schemaTest_objectPropertiesNotObject() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : [ "name", "age" ], + "additionalProperties" : false, + "required" : [ "name", "age" ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'properties' field is not a non-empty object.") + } + + @Test + fun schemaTest_objectPropertiesEmpty() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { }, + "additionalProperties" : false, + "required" : [ ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: 'properties' field is not a non-empty object.") + } + + @Test + fun schemaTest_anyOfInRootSchema() { + // OpenAI does not allow `"anyOf"` to appear at the root level of a schema. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "anyOf" : [ { + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "additionalProperties" : false, + "required" : ["name"] + }, { + "type" : "array", + "items" : { + "type" : "object", + "properties" : { "name" : { "type" : "string" } }, + "additionalProperties" : false, + "required" : ["name"] + } + } ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]).isEqualTo("#: Root schema contains 'anyOf' field.") + } + + @Test + fun schemaTest_anyOfNotArray() { + // Unlikely that this can occur in a generated schema, so this is more about code coverage. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "name" : { + "anyOf" : { + "type" : "string" + } + } + }, + "additionalProperties" : false, + "required" : ["name"] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/properties/name: 'anyOf' field is not a non-empty array.") + } + + @Test + fun schemaTest_anyOfIsEmptyArray() { + // Unlikely that this can occur in a generated schema, so this is more about code coverage. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "name" : { + "anyOf" : [ ] + } + }, + "additionalProperties" : false, + "required" : ["name"] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/properties/name: 'anyOf' field is not a non-empty array.") + } + + @Test + fun schemaTest_anyOfInSubSchemaArray() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "value" : { + "anyOf" : [ + { "type" : "string" }, + { "type" : "number" } + ] + } + }, + "additionalProperties" : false, + "required" : ["value"] + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_noSchemaFieldRootSchema() { + @Suppress("unused") class X(val s: String) + + schema = extractSchema(X::class.java) + (schema as ObjectNode).remove(SCHEMA) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]).isEqualTo("#: Root schema missing '$SCHEMA' field.") + } + + @Test + @Suppress("unused") + fun schemaTest_deepNestingAtLimit() { + class U(val s: String) + class V(val u: U) + class W(val v: V) + class X(val w: W) + class Y(val x: X) + + schema = extractSchema(Y::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + @Suppress("unused") + fun schemaTest_deepNestingBeyondLimit() { + class U(val s: String) + class V(val u: U) + class W(val v: V) + class X(val w: W) + class Y(val x: X) + class Z(val y: Y) + + schema = extractSchema(Z::class.java) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]).contains("Current nesting depth is 6, but maximum is 5.") + } + + @Test + fun schemaTest_stringEnum250ValueOverSizeLimit() { + // OpenAI specification: "For a single enum property with string values, the total string + // length of all enum values cannot exceed 7,500 characters when there are more than 250 + // enum values." + + // This test creates an enum with exactly 250 string values with more than 7,500 characters + // in total (31 characters per value for a total of 7,750 characters). No error is expected. + val values = (1..250).joinToString(", ") { "\"%s%03d\"".format("x".repeat(28), it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "string", + "enum" : [ $values ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_stringEnum251ValueUnderSizeLimit() { + // This test creates an enum with exactly 251 string values with fewer than 7,500 characters + // in total (29 characters per value for a total of 7,279 characters). No error is expected. + val values = (1..251).joinToString(", ") { "\"%s%03d\"".format("x".repeat(26), it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "string", + "enum" : [ $values ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_stringEnum251ValueOverSizeLimit() { + // This test creates an enum with exactly 251 string values with fewer than 7,500 characters + // in total (30 characters per value for a total of 7,530 characters). An error is expected. + val values = (1..251).joinToString(", ") { "\"%s%03d\"".format("x".repeat(27), it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "string", + "enum" : [ $values ] + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo( + "#/enum: Total string length (7530) of values of an enum " + + "with 251 values exceeds limit of 7500." + ) + } + + @Test + fun schemaTest_totalEnumValuesAtLimit() { + // OpenAI specification: "A schema may have up to 500 enum values across all enum + // properties." + + // This test creates two enums with a total of 500 values. The total string length of the + // values is well within the limits (2,000 characters). + val valuesA = (1..250).joinToString(", ") { "\"a%03d\"".format(it) } + val valuesB = (1..250).joinToString(", ") { "\"b%03d\"".format(it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "a" : { + "type" : "string", + "enum" : [ $valuesA ] + }, + "b" : { + "type" : "string", + "enum" : [ $valuesB ] + } + }, + "required" : [ "a", "b" ], + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_totalEnumValuesOverLimit() { + // This test creates two enums with a total of 501 values. The total string length of the + // values is well within the limits (2,004 characters). + val valuesA = (1..250).joinToString(", ") { "\"a%03d\"".format(it) } + val valuesB = (1..251).joinToString(", ") { "\"b%03d\"".format(it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "a" : { + "type" : "string", + "enum" : [ $valuesA ] + }, + "b" : { + "type" : "string", + "enum" : [ $valuesB ] + } + }, + "required" : [ "a", "b" ], + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: Total number of enum values (501) exceeds limit of 500.") + } + + @Test + fun schemaTest_maxObjectPropertiesAtLimit() { + // This test creates two object schemas with a total of 100 object properties. OpenAI does + // not support more than 100 properties total in the whole schema. Two objects are used to + // ensure that counting is not done per object, but across all objects. Note that each + // object schema is itself a property, so there are two properties at the top level and 49 + // properties each at the next level. No error is expected, as the limit is not exceeded. + val propUses = + (1..49).joinToString(", ") { "\"x%02d\" : { \"type\" : \"string\" }".format(it) } + val propNames = (1..49).joinToString(", ") { "\"x%02d\"".format(it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "a" : { + "type" : "object", + "properties" : { + $propUses + }, + "required" : [ $propNames ], + "additionalProperties" : false + }, + "b" : { + "type" : "object", + "properties" : { + $propUses + }, + "required" : [ $propNames ], + "additionalProperties" : false + } + }, + "required" : [ "a", "b" ], + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_maxObjectPropertiesOverLimit() { + // This test creates two object schemas with a total of 101 object properties. OpenAI does + // not support more than 100 properties total in the whole schema. Expect an error. + val propUses = + (1..49).joinToString(", ") { "\"x_%02d\" : { \"type\" : \"string\" }".format(it) } + val propNames = (1..49).joinToString(", ") { "\"x_%02d\"".format(it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "type" : "object", + "properties" : { + "a" : { + "type" : "object", + "properties" : { + $propUses + }, + "required" : [ $propNames ], + "additionalProperties" : false + }, + "b" : { + "type" : "object", + "properties" : { + $propUses, + "property_101" : { "type" : "string" } + }, + "required" : [ $propNames, "property_101" ], + "additionalProperties" : false + } + }, + "required" : [ "a", "b" ], + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: Total number of object properties (101) exceeds limit of 100.") + } + + @Test + fun schemaTest_maxStringLengthAtLimit() { + // OpenAI specification: "In a schema, total string length of all property names, definition + // names, enum values, and const values cannot exceed 15,000 characters." + // + // This test creates a schema with many property names, definition names, enum values, and + // const values calculated to have a total string length of 15,000 characters. No error is + // expected. + // + // The test creates a schema that looks like the following, with the numbers adjusted to + // achieve a total of 15,000 characters for the relevant elements. + // + // { + // "$schema" : "...", + // "$defs" : { + // "d_001" : { + // "type" : "string", + // "const" : "c_001" + // }, + // ..., + // "d_nnn" : { + // "type" : "string", + // "const" : "c_nnn" + // } + // }, + // "type" : "object", + // "properties" : { + // "p_001" : { + // "type" : "string", + // "enum" : [ "eeeee..._001", ..., "eeeee..._nnn" ] + // }, + // ..., + // "p_nnn" : { + // "type" : "string", + // "enum" : [ "eeeee..._001", ..., "eeeee..._nnn" ] + // } + // }, + // "required" : [ "p_001", ..., "p_nnn" ], + // "additionalProperties" : false + // } + + val numDefs = 65 // Each also has one "const" value. + val numProps = 70 // Each also has "numEnumValues" enum values. + val nameLen = 5 // Length of names of definitions, properties and const values. + val numEnumValues = 5 // numProps * numEnumValues <= 500 limit (OpenAI) + val enumValueLen = 40 // Length of enum values. + val expectedTotalStringLength = + nameLen * (numProps + numDefs * 2) + numProps * enumValueLen * numEnumValues + + val enumValues = + (1..numEnumValues).joinToString(", ") { "\"%s_%03d\"".format("e".repeat(36), it) } + val defs = + (1..numDefs).joinToString(", ") { + "\"d_%03d\" : { \"type\" : \"string\", \"const\" : \"c_%03d\" }".format(it, it) + } + val props = + (1..numProps).joinToString(", ") { + "\"p_%03d\" : { \"type\" : \"string\", \"enum\" : [ $enumValues ] }".format(it) + } + val propNames = (1..numProps).joinToString(", ") { "\"p_%03d\"".format(it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "$DEFS" : { $defs }, + "type" : "object", + "properties" : { $props }, + "required" : [ $propNames ], + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(expectedTotalStringLength).isEqualTo(15_000) // Exactly on the limit. + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_maxStringLengthOverLimit() { + // OpenAI specification: "In a schema, total string length of all property names, definition + // names, enum values, and const values cannot exceed 15,000 characters." + // + // This test creates a schema with many property names, definition names, enum values, and + // const values calculated to have a total string length of just over 15,000 characters. An + // error is expected. + + val numDefs = 66 // Each also has one "const" value. + val numProps = 70 // Each also has "numEnumValues" enum values. + val numEnumValues = 5 // numProps * numEnumValues <= 500 limit (OpenAI) + val nameLen = 5 // Length of names of definitions, properties and const values. + val enumValueLen = 40 // Length of enum values. + val expectedTotalStringLength = + nameLen * (numProps + numDefs * 2) + numProps * enumValueLen * numEnumValues + + val enumValues = + (1..numEnumValues).joinToString(", ") { "\"%s_%03d\"".format("e".repeat(36), it) } + val defs = + (1..numDefs).joinToString(", ") { + "\"d_%03d\" : { \"type\" : \"string\", \"const\" : \"c_%03d\" }".format(it, it) + } + val props = + (1..numProps).joinToString(", ") { + "\"p_%03d\" : { \"type\" : \"string\", \"enum\" : [ $enumValues ] }".format(it) + } + val propNames = (1..numProps).joinToString(", ") { "\"p_%03d\"".format(it) } + + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "$DEFS" : { $defs }, + "type" : "object", + "properties" : { $props }, + "required" : [ $propNames ], + "additionalProperties" : false + } + """ + ) + validator.validate(schema) + + assertThat(expectedTotalStringLength).isGreaterThan(15_000) + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#: Total string length of all values (15010) exceeds limit of 15000.") + } + + @Test + fun schemaTest_annotatedWithJsonClassDescription() { + // Add a "description" to the root schema using an annotation. + @JsonClassDescription("A simple schema.") class X() + + schema = extractSchema(X::class.java) + validator.validate(schema) + + // Assume that the schema is well-formed. + val desc = schema.get("description") + + assertThat(validator.isValid()).isTrue + assertThat(desc).isNotNull + assertThat(desc.isTextual).isTrue + assertThat(desc.asText()).isEqualTo("A simple schema.") + } + + @Test + fun schemaTest_annotatedWithJsonPropertyDescription() { + // Add a "description" to the property using an annotation. + @Suppress("unused") class X(@get:JsonPropertyDescription("A string value.") val s: String) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + // Assume that the schema is well-formed. + val properties = schema.get("properties") + val stringProperty = properties.get("s") + val desc = stringProperty.get("description") + + assertThat(validator.isValid()).isTrue + assertThat(desc).isNotNull + assertThat(desc.isTextual).isTrue + assertThat(desc.asText()).isEqualTo("A string value.") + } + + @Test + fun schemaTest_annotatedWithJsonProperty() { + // Override the default name of the property using the annotation. + @Suppress("unused") class X(@get:JsonProperty("a_string") val s: String) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + // Assume that the schema is well-formed. + val properties = schema.get("properties") + val stringProperty = properties.get("a_string") + + assertThat(validator.isValid()).isTrue + assertThat(stringProperty).isNotNull + } + + @Test + fun schemaTest_annotatedWithJsonPropertyRejectDefaultValue() { + // Set a default value for the property. It should be ignored when the schema is generated, + // as default property values are not supported in OpenAI JSON schemas. (The Victools docs + // have examples of how to add support for this default values via annotations or initial + // values, should support for default values be needed in the future.) + // + // Lack of support is not mentioned in the specification, but see the evidence at: + // https://engineering.fractional.ai/openai-structured-output-fixes + @Suppress("unused") + class X( + @get:JsonProperty(defaultValue = "default_value_1") val s: String = "default_value_2" + ) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + // Assume that the schema is well-formed. + val properties = schema.get("properties") + val stringProperty = properties.get("s") + + assertThat(validator.isValid()).isTrue + assertThat(stringProperty).isNotNull + assertThat(stringProperty.get("default")).isNull() + } + + @Test + fun schemaTest_annotatedWithJsonIgnore() { + // Override the default name of the property using the annotation. + @Suppress("unused") class X(@get:JsonIgnore val s1: String, val s2: String) + + schema = extractSchema(X::class.java) + validator.validate(schema) + + // Assume that the schema is well-formed. + val properties = schema.get("properties") + val s1Property = properties.get("s1") + val s2Property = properties.get("s2") + + assertThat(validator.isValid()).isTrue + assertThat(s1Property).isNull() + assertThat(s2Property).isNotNull + } + + @Test + fun schemaTest_emptyDefinitions() { + // Be lenient about empty definitions. + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "$DEFS" : { }, + "type" : "string" + } + """ + ) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun schemaTest_referenceMissingReferent() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "$DEFS" : { }, + "$REF" : "#/$DEFS/Person" + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]) + .isEqualTo("#/$REF: Invalid or unsupported reference: '#/$DEFS/Person'.") + } + + @Test + fun schemaTest_referenceFieldIsNotTextual() { + schema = + parseJson( + """ + { + "$SCHEMA" : "$SCHEMA_VER", + "$DEFS" : { }, + "$REF" : 42 + } + """ + ) + validator.validate(schema) + + assertThat(validator.errors()).hasSize(1) + assertThat(validator.errors()[0]).isEqualTo("#/$REF: '$REF' field is not a text value.") + } + + @Test + fun validatorBeforeValidation() { + assertThat(validator.errors()).isEmpty() + assertThat(validator.isValid()).isFalse + } + + @Test + fun validatorReused() { + class X() + + schema = extractSchema(X::class.java) + validator.validate(schema) + + // Should fail if an attempt is made to reuse the validator. + assertThatThrownBy { validator.validate(schema) } + .isExactlyInstanceOf(IllegalStateException::class.java) + .hasMessageContaining("Validation already complete.") + } + + @Test + @Suppress("unused") + fun schemaTest_largeLaureatesSchema() { + // This covers many cases: large and complex "$defs", resolution of references, recursive + // references, etc. The output is assumed to be good (it has been checked by eye) and the + // test just shows that the validator can handle the complexity without crashing or emitting + // spurious errors. + class Name(val givenName: String, val familyName: String) + + class Person( + @get:JsonPropertyDescription("The name of the person.") val name: Name, + @get:JsonProperty(value = "date_of_birth", defaultValue = "unknown_1") + @get:JsonPropertyDescription("The date of birth of the person.") + var dateOfBirth: String, + @get:JsonPropertyDescription("The country of citizenship of the person.") + var nationality: String, + // A child being a `Person` results in a recursive schema. + @get:JsonPropertyDescription("The children (if any) of the person.") + val children: List, + ) { + @get:JsonPropertyDescription("The other name of the person.") + var otherName: Name = Name("Bob", "Smith") + } + + class Laureate( + val laureate: Person, + val majorContribution: String, + val yearOfWinning: String, + @get:JsonIgnore val favoriteColor: String, + ) + + class Laureates( + // Two lists results in a `Laureate` definition that is referenced in the schema. + var laureates1901to1950: List, + var laureates1951to2025: List, + ) + + schema = extractSchema(Laureates::class.java) + validator.validate(schema) + + assertThat(validator.isValid()).isTrue + } + + @Test + fun fromJsonSuccess() { + @Suppress("unused") class X(val s: String) + + val x = responseTypeFromJson("{\"s\" : \"hello\"}", X::class.java) + + assertThat(x.s).isEqualTo("hello") + } + + @Test + fun fromJsonFailure1() { + @Suppress("unused") class X(val s: String) + + // Well-formed JSON, but it does not match the schema of class `X`. + assertThatThrownBy { responseTypeFromJson("{\"wrong\" : \"hello\"}", X::class.java) } + .isExactlyInstanceOf(OpenAIInvalidDataException::class.java) + .hasMessage("Error parsing JSON: {\"wrong\" : \"hello\"}") + } + + @Test + fun fromJsonFailure2() { + @Suppress("unused") class X(val s: String) + + // Malformed JSON. + assertThatThrownBy { responseTypeFromJson("{\"truncated", X::class.java) } + .isExactlyInstanceOf(OpenAIInvalidDataException::class.java) + .hasMessage("Error parsing JSON: {\"truncated") + } + + @Test + fun fromClassEnablesStrictAdherenceToSchema() { + @Suppress("unused") class X(val s: String) + + val jsonSchema = responseFormatFromClass(X::class.java) + + // The "strict" flag _must_ be set to ensure that the model's output will _always_ conform + // to the JSON schema. + assertThat(jsonSchema.jsonSchema().strict()).isPresent + assertThat(jsonSchema.jsonSchema().strict().get()).isTrue + } + + @Test + @Suppress("unused") + fun fromClassSuccessWithoutValidation() { + // Exceed the maximum nesting depth, but do not enable validation. + class U(val s: String) + class V(val u: U) + class W(val v: V) + class X(val w: W) + class Y(val x: X) + class Z(val y: Y) + + assertThatNoException().isThrownBy { + responseFormatFromClass(Z::class.java, JsonSchemaLocalValidation.NO) + } + } + + @Test + fun fromClassSuccessWithValidation() { + @Suppress("unused") class X(val s: String) + + assertThatNoException().isThrownBy { + responseFormatFromClass(X::class.java, JsonSchemaLocalValidation.YES) + } + } + + @Test + @Suppress("unused") + fun fromClassFailureWithValidation() { + // Exceed the maximum nesting depth and enable validation. + class U(val s: String) + class V(val u: U) + class W(val v: V) + class X(val w: W) + class Y(val x: X) + class Z(val y: Y) + + assertThatThrownBy { responseFormatFromClass(Z::class.java, JsonSchemaLocalValidation.YES) } + .isExactlyInstanceOf(IllegalArgumentException::class.java) + .hasMessage( + "Local validation failed for JSON schema derived from ${Z::class.java}:\n" + + " - #/properties/y/properties/x/properties/w/properties/v/properties/u" + + "/properties/s: Current nesting depth is 6, but maximum is 5." + ) + } + + @Test + @Suppress("unused") + fun fromClassFailureWithValidationDefault() { + // Confirm that the default value of the `localValidation` argument is `true` by expecting + // a validation error when that argument is not given an explicit value. + class U(val s: String) + class V(val u: U) + class W(val v: V) + class X(val w: W) + class Y(val x: X) + class Z(val y: Y) + + // Use default for `localValidation` flag. + assertThatThrownBy { responseFormatFromClass(Z::class.java) } + .isExactlyInstanceOf(IllegalArgumentException::class.java) + .hasMessage( + "Local validation failed for JSON schema derived from ${Z::class.java}:\n" + + " - #/properties/y/properties/x/properties/w/properties/v/properties/u" + + "/properties/s: Current nesting depth is 6, but maximum is 5." + ) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt b/openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt new file mode 100644 index 000000000..c62eb8ed9 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/core/StructuredOutputsTestUtils.kt @@ -0,0 +1,366 @@ +package com.openai.core + +import java.lang.reflect.Method +import java.util.Optional +import kotlin.reflect.KClass +import kotlin.reflect.KFunction +import kotlin.reflect.KVisibility +import kotlin.reflect.full.declaredFunctions +import kotlin.reflect.jvm.javaMethod +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.fail +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +// Constants for values that can be used in many of the tests as sample input or output values. +// +// Where a function returns `Optional`, `JsonField` or `JsonValue` There is no need to provide +// a value that matches the type ``, a simple `String` value of `"a-string"` will work OK. +internal const val STRING = "a-string" +internal val NULLABLE_STRING: String? = null +internal val OPTIONAL = Optional.of(STRING) +internal val JSON_FIELD = JsonField.of(STRING) +internal val JSON_VALUE = JsonValue.from(STRING) +internal val NULLABLE = null +internal const val BOOLEAN: Boolean = true +internal val NULLABLE_BOOLEAN: Boolean? = null +internal const val LONG: Long = 42L +internal val NULLABLE_LONG: Long? = null +internal const val DOUBLE: Double = 42.0 +internal val NULLABLE_DOUBLE: Double? = null +internal val LIST = listOf(STRING) +internal val SET = setOf(STRING) +internal val MAP = mapOf(STRING to STRING) + +/** + * Defines a test case where a function in a delegator returns a value from a corresponding function + * in a delegate. + */ +internal data class DelegationReadTestCase(val functionName: String, val expectedValue: Any) + +/** + * Defines a test case where a function in a delegator passes its parameters through to a + * corresponding function in a delegate. + */ +// Want `vararg`, so cannot use `data class`. Needs a custom `toString`, anyway. +internal class DelegationWriteTestCase( + val functionName: String, + /** + * The values to pass to the function being tested. If the first input value is `null`, it must + * be the only value. Only the first input value may be `null`, all others must be non-`null`. + * This is not enforced by this class, but is assumed by the related utility functions. + */ + vararg val inputValues: Any?, +) { + /** Gets the string representation that identifies the test function when running JUnit. */ + override fun toString(): String = + "$functionName(${inputValues.joinToString(", ") { + it?.javaClass?.simpleName ?: "null" + }})" +} + +/** A basic class used as the generic type when testing. */ +internal class X(val s: String) { + override fun equals(other: Any?) = other is X && other.s == s + + override fun hashCode() = s.hashCode() +} + +/** + * Checks that all functions in one class have a corresponding function with the same name and + * parameter types in another class. A list of function names that should be allowed as exceptions + * can be given. Non-public functions are ignored, as they are considered to be implementation + * details of each class. + * + * Call this function twice, changing the order of the two classes to ensure that both classes + * contain the same set of functions (barring exceptions), should that be the expectation. + * + * @param subsetClass The class whose functions should be a subset of the functions of the other + * class. + * @param supersetClass The class whose functions should be a superset of the functions of the other + * class. + */ +internal fun checkAllDelegation( + subsetClass: KClass<*>, + supersetClass: KClass<*>, + vararg exceptFunctionNames: String, +) { + assertThat(subsetClass != supersetClass) + .describedAs { "The two classes should not be the same." } + .isTrue + + val subsetFunctions = subsetClass.declaredFunctions + val missingFunctions = mutableListOf>() + + for (subsetFunction in subsetFunctions) { + if (subsetFunction.visibility != KVisibility.PUBLIC) { + continue + } + + if (subsetFunction.name in exceptFunctionNames) { + continue + } + + // Drop the first parameter from each function, as it is the implicit "this" object and has + // the type of the class declaring the function, which will never match. + val supersetFunction = + supersetClass.declaredFunctions.find { + it.name == subsetFunction.name && + it.parameters.drop(1).map { it.type } == + subsetFunction.parameters.drop(1).map { it.type } + } + + if (supersetFunction == null) { + missingFunctions.add(subsetFunction) + } + } + + assertThat(missingFunctions) + .describedAs { + "Function(s) not found in ${supersetClass.simpleName}:\n" + + missingFunctions.joinToString("\n") { " - $it" } + } + .isEmpty() +} + +/** + * Checks that the delegator function calls the corresponding delegate function and no other + * functions on the delegate. The test case defines the function name and the sample return value. + * All functions take no arguments. + */ +internal fun checkOneDelegationRead( + delegator: Any, + mockDelegate: Any, + testCase: DelegationReadTestCase, +) { + // Stub the method in the mock delegate using reflection + val delegateMethod = mockDelegate::class.java.getMethod(testCase.functionName) + `when`(delegateMethod.invoke(mockDelegate)).thenReturn(testCase.expectedValue) + + // Call the corresponding method on the delegator using reflection + val delegatorMethod = delegator::class.java.getMethod(testCase.functionName) + val result = delegatorMethod.invoke(delegator) + + // Verify that the corresponding method on the mock delegate was called exactly once + verify(mockDelegate, times(1)).apply { delegateMethod.invoke(mockDelegate) } + verifyNoMoreInteractions(mockDelegate) + + // Assert that the result matches the expected value + assertThat(result).isEqualTo(testCase.expectedValue) +} + +/** + * Checks that the delegator function calls the corresponding delegate function and no other + * functions on the delegate. The test case defines the function name and sample parameter values. + */ +internal fun checkOneDelegationWrite( + delegator: Any, + mockDelegate: Any, + testCase: DelegationWriteTestCase, +) { + invokeMethod(findDelegationMethod(delegator, testCase), delegator, testCase) + + // Verify that the corresponding method on the mock delegate was called exactly once. + verify(mockDelegate, times(1)).apply { + invokeMethod(findDelegationMethod(mockDelegate, testCase), mockDelegate, testCase) + } + verifyNoMoreInteractions(mockDelegate) +} + +private fun invokeMethod(method: Method, target: Any, testCase: DelegationWriteTestCase) { + val numParams = testCase.inputValues.size + val inputValue1 = testCase.inputValues[0] + val inputValue2 = testCase.inputValues.getOrNull(1) + + when (numParams) { + 1 -> method.invoke(target, inputValue1) + 2 -> method.invoke(target, inputValue1, inputValue2) + else -> fail { "Unexpected number of function parameters ($numParams)." } + } +} + +/** + * Finds the java method matching the test case's function name and parameter types in the delegator + * or delegate `target`. + */ +internal fun findDelegationMethod(target: Any, testCase: DelegationWriteTestCase): Method { + val numParams = testCase.inputValues.size + val inputValue1: Any? = testCase.inputValues[0] + val inputValue2 = if (numParams > 1) testCase.inputValues[1] else null + + val method = + when (numParams) { + 1 -> + if (inputValue1 != null) { + findJavaMethod( + target.javaClass, + testCase.functionName, + toJavaType(inputValue1.javaClass), + ) + } else { + // Only the first parameter may be nullable and only if it is the only + // parameter. If the first parameter is nullable, it will be the only function + // of the same name with a nullable first parameter. To handle the potentially + // nullable first parameter, Kotlin reflection is needed. This allows a function + // `f(Boolean)` to be distinguished from `f(Boolean?)`. For the tests, if the + // parameter type is nullable, the parameter value will always be `null` (if + // not, the function with the nullable parameter would not be matched). + // + // Using Kotlin reflection, the first parameter (zero index) is `this` object, + // so start matching from the second parameter onwards. + target::class + .declaredFunctions + .find { + it.name == testCase.functionName && + it.parameters[1].type.isMarkedNullable + } + ?.javaMethod + } + + 2 -> + if (inputValue1 != null && inputValue2 != null) { + findJavaMethod( + target.javaClass, + testCase.functionName, + toJavaType(inputValue1.javaClass), + toJavaType(inputValue2.javaClass), + ) + } else { + // There are no instances where there are two parameters and one of them is + // nullable. + fail { "Function $testCase second parameter must not be null." } + } + + else -> fail { "Function $testCase has unsupported number of parameters." } + } ?: fail { "Function $testCase cannot be found in $target." } + + // Using `fail` conditionally above, so the compiler knows the code will not continue and can + // infer that `method` is not null. It cannot do that for `assertThat...isNotNull`. + return method +} + +/** Finds a Java method in a class that matches a method name and a list of parameter types. */ +private fun findJavaMethod( + clazz: Class<*>, + methodName: String, + vararg parameterTypes: Class<*>, +): Method? = + clazz.declaredMethods.firstOrNull { method -> + method.name == methodName && + method.parameterTypes.size == parameterTypes.size && + method.parameterTypes.indices.all { index -> + (parameterTypes[index].isPrimitive && + method.parameterTypes[index] == parameterTypes[index]) || + method.parameterTypes[index].isAssignableFrom(parameterTypes[index]) + } + } + +/** + * Returns the Java type to use when matching type parameters for a Java method. The type is the + * type of the input value that will be used when the method is invoked. For most types, the given + * type is returned. However, if the type represents a Kotlin primitive, it will be converted to a + * Java primitive. This allows matching of methods with parameter types that are non-nullable Kotlin + * primitives. If not translated, methods with parameter types that are nullable Kotlin primitives + * would always be matched instead. + */ +private fun toJavaType(type: Class<*>) = + when (type) { + // This only needs to cover the types used in the test cases. + java.lang.Long::class.java -> java.lang.Long.TYPE + java.lang.Boolean::class.java -> java.lang.Boolean.TYPE + java.lang.Double::class.java -> java.lang.Double.TYPE + else -> type + } + +/** + * Checks that all delegating functions in a delegator class have corresponding unit tests. The + * read-only functions should take no parameters; only return a value. + * + * @param delegatorClass The delegator class whose functions are tested. Every named function in + * this class must be identified in one of the given sources of function names or a failure will + * occur. + * @param delegationTestCases The tests cases that identify the names of delegating functions for + * which parameterized unit tests have been defined. + * @param exceptionalTestedFns The names of delegating functions that are tested separately, not as + * parameterized unit tests. This is usually because they require special handling in the test. + * @param nonDelegatingFns The names of functions that do not perform any delegation and for which + * delegation tests are not required. + */ +internal fun checkAllDelegatorReadFunctionsAreTested( + delegatorClass: KClass<*>, + delegationTestCases: List, + exceptionalTestedFns: Set, + nonDelegatingFns: Set, +) { + val testedFns = delegationTestCases.map { it.functionName }.toSet() + exceptionalTestedFns + val delegatorFunctions = delegatorClass.declaredFunctions + val untestedFunctions = + delegatorFunctions.filter { it.name !in testedFns && it.name !in nonDelegatingFns } + + assertThat(untestedFunctions) + .describedAs( + "Delegation is not tested for function(s):\n" + + untestedFunctions.joinToString("\n") { " - $it" } + ) + .isEmpty() +} + +/** + * Checks that all delegating functions in a delegator class have corresponding unit tests. The + * write-only functions should take parameters and return no value. + * + * @param delegatorClass The delegator class whose functions are tested. Every named function in + * this class must be identified in one of the given sources of function names or a failure will + * occur. + * @param delegationTestCases The tests cases that identify the names of delegating functions for + * which parameterized unit tests have been defined. + * @param exceptionalTestedFns The names of delegating functions that are tested separately, not as + * parameterized unit tests. This is usually because they require special handling in the test. + * @param nonDelegatingFns The names of functions that do not perform any delegation and for which + * delegation tests are not required. + */ +internal fun checkAllDelegatorWriteFunctionsAreTested( + delegatorClass: KClass<*>, + delegationTestCases: List, + exceptionalTestedFns: Set, + nonDelegatingFns: Set, +) { + // There are exceptional test cases for some functions. Most other functions are part of the + // list of those using the parameterized test. There are many overloaded functions, so the + // approach here is to build a list (_not_ a set) of all function names and then "subtract" + // those for which tests are defined and see what remains. For example, there could be eight + // `addMessage` functions, so there must be eight tests defined for functions named `addMessage` + // that will be subtracted from the list of functions matching that name. Parameter types are + // not checked, as that is awkward and probably overkill. Therefore, this scheme is not reliable + // if a function is tested more than once. + val testedFns = + (delegationTestCases.map { it.functionName } + exceptionalTestedFns).toMutableList() + // Only interested in the names of the functions (which may contain duplicates): parameters are + // not matched, so any signatures could be misleading when reporting errors. + val delegatorFns = delegatorClass.declaredFunctions.map { it.name }.toMutableList() + + // Making modifications to the list, so clone it with `toList()` before iterating. + for (fnName in delegatorFns.toList()) { + if (fnName in testedFns) { + testedFns.remove(fnName) + delegatorFns.remove(fnName) + } + if (fnName in nonDelegatingFns) { + delegatorFns.remove(fnName) + } + } + + // If there are function names remaining in `delegatorFns`, then there are tests missing. + assertThat(delegatorFns) + .describedAs { "Delegation is not tested for functions $delegatorFns." } + .isEmpty() + + // If there are function names remaining in `testedFns`, then there are more tests than there + // should be. Functions might be tested twice, or there may be tests for functions that have + // since been removed from the delegate (though those tests probably failed). + assertThat(testedFns) + .describedAs { "Unexpected or redundant tests for functions $testedFns." } + .isEmpty() +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateResponseTest.kt index 0a7c3f77f..8f64d432c 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionCreateResponseTest.kt @@ -66,18 +66,18 @@ internal class TranscriptionCreateResponseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() ) - .addWord(TranscriptionWord.builder().end(0.0).start(0.0).word("word").build()) + .addWord(TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build()) .build() val transcriptionCreateResponse = TranscriptionCreateResponse.ofVerbose(verbose) @@ -98,18 +98,18 @@ internal class TranscriptionCreateResponseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() ) - .addWord(TranscriptionWord.builder().end(0.0).start(0.0).word("word").build()) + .addWord(TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build()) .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegmentTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegmentTest.kt index 127ee6b96..85eef2387 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegmentTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionSegmentTest.kt @@ -14,25 +14,25 @@ internal class TranscriptionSegmentTest { val transcriptionSegment = TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() assertThat(transcriptionSegment.id()).isEqualTo(0L) - assertThat(transcriptionSegment.avgLogprob()).isEqualTo(0.0) - assertThat(transcriptionSegment.compressionRatio()).isEqualTo(0.0) - assertThat(transcriptionSegment.end()).isEqualTo(0.0) - assertThat(transcriptionSegment.noSpeechProb()).isEqualTo(0.0) + assertThat(transcriptionSegment.avgLogprob()).isEqualTo(0.0f) + assertThat(transcriptionSegment.compressionRatio()).isEqualTo(0.0f) + assertThat(transcriptionSegment.end()).isEqualTo(0.0f) + assertThat(transcriptionSegment.noSpeechProb()).isEqualTo(0.0f) assertThat(transcriptionSegment.seek()).isEqualTo(0L) - assertThat(transcriptionSegment.start()).isEqualTo(0.0) - assertThat(transcriptionSegment.temperature()).isEqualTo(0.0) + assertThat(transcriptionSegment.start()).isEqualTo(0.0f) + assertThat(transcriptionSegment.temperature()).isEqualTo(0.0f) assertThat(transcriptionSegment.text()).isEqualTo("text") assertThat(transcriptionSegment.tokens()).containsExactly(0L) } @@ -43,13 +43,13 @@ internal class TranscriptionSegmentTest { val transcriptionSegment = TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() diff --git a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionVerboseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionVerboseTest.kt index 6c3ceef9d..8f0a543fd 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionVerboseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionVerboseTest.kt @@ -20,18 +20,18 @@ internal class TranscriptionVerboseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() ) - .addWord(TranscriptionWord.builder().end(0.0).start(0.0).word("word").build()) + .addWord(TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build()) .build() assertThat(transcriptionVerbose.duration()).isEqualTo(0.0) @@ -41,19 +41,19 @@ internal class TranscriptionVerboseTest { .containsExactly( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() ) assertThat(transcriptionVerbose.words().getOrNull()) - .containsExactly(TranscriptionWord.builder().end(0.0).start(0.0).word("word").build()) + .containsExactly(TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build()) } @Test @@ -67,18 +67,18 @@ internal class TranscriptionVerboseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() ) - .addWord(TranscriptionWord.builder().end(0.0).start(0.0).word("word").build()) + .addWord(TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build()) .build() val roundtrippedTranscriptionVerbose = diff --git a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionWordTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionWordTest.kt index 0bf1311aa..518a754ec 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionWordTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/audio/transcriptions/TranscriptionWordTest.kt @@ -11,17 +11,19 @@ internal class TranscriptionWordTest { @Test fun create() { - val transcriptionWord = TranscriptionWord.builder().end(0.0).start(0.0).word("word").build() + val transcriptionWord = + TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build() - assertThat(transcriptionWord.end()).isEqualTo(0.0) - assertThat(transcriptionWord.start()).isEqualTo(0.0) + assertThat(transcriptionWord.end()).isEqualTo(0.0f) + assertThat(transcriptionWord.start()).isEqualTo(0.0f) assertThat(transcriptionWord.word()).isEqualTo("word") } @Test fun roundtrip() { val jsonMapper = jsonMapper() - val transcriptionWord = TranscriptionWord.builder().end(0.0).start(0.0).word("word").build() + val transcriptionWord = + TranscriptionWord.builder().end(0.0f).start(0.0f).word("word").build() val roundtrippedTranscriptionWord = jsonMapper.readValue( diff --git a/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateResponseTest.kt index 53fc2b4f1..098a9b842 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationCreateResponseTest.kt @@ -50,13 +50,13 @@ internal class TranslationCreateResponseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() @@ -81,13 +81,13 @@ internal class TranslationCreateResponseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() diff --git a/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationVerboseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationVerboseTest.kt index fc5baf5d4..7b318663e 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationVerboseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/audio/translations/TranslationVerboseTest.kt @@ -21,13 +21,13 @@ internal class TranslationVerboseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() @@ -41,13 +41,13 @@ internal class TranslationVerboseTest { .containsExactly( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() @@ -65,13 +65,13 @@ internal class TranslationVerboseTest { .addSegment( TranscriptionSegment.builder() .id(0L) - .avgLogprob(0.0) - .compressionRatio(0.0) - .end(0.0) - .noSpeechProb(0.0) + .avgLogprob(0.0f) + .compressionRatio(0.0f) + .end(0.0f) + .noSpeechProb(0.0f) .seek(0L) - .start(0.0) - .temperature(0.0) + .start(0.0f) + .temperature(0.0f) .text("text") .addToken(0L) .build() diff --git a/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParamsTest.kt index e47aebd6b..6ae11ba15 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParamsTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/ChatCompletionCreateParamsTest.kt @@ -347,4 +347,36 @@ internal class ChatCompletionCreateParamsTest { ) assertThat(body.model()).isEqualTo(ChatModel.GPT_4_1) } + + @Test + fun structuredOutputsBuilder() { + class X(val s: String) + + // Only interested in a few things: + // - Does the `Builder` type change when `responseFormat(Class)` is called? + // - Are values already set on the "old" `Builder` preserved in the change-over? + // - Can new values be set on the "new" `Builder` alongside the "old" values? + val params = + ChatCompletionCreateParams.builder() + .addDeveloperMessage("dev message") + .model(ChatModel.GPT_4_1) + .responseFormat(X::class.java) // Creates and return a new builder. + .addSystemMessage("sys message") + .build() + + val body = params.rawParams._body() + + assertThat(params).isInstanceOf(StructuredChatCompletionCreateParams::class.java) + assertThat(params.responseType).isEqualTo(X::class.java) + assertThat(body.messages()) + .containsExactly( + ChatCompletionMessageParam.ofDeveloper( + ChatCompletionDeveloperMessageParam.builder().content("dev message").build() + ), + ChatCompletionMessageParam.ofSystem( + ChatCompletionSystemMessageParam.builder().content("sys message").build() + ), + ) + assertThat(body.model()).isEqualTo(ChatModel.GPT_4_1) + } } diff --git a/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt new file mode 100644 index 000000000..4b2891982 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionCreateParamsTest.kt @@ -0,0 +1,318 @@ +package com.openai.models.chat.completions + +import com.openai.core.BOOLEAN +import com.openai.core.DOUBLE +import com.openai.core.DelegationWriteTestCase +import com.openai.core.JSON_FIELD +import com.openai.core.JSON_VALUE +import com.openai.core.LIST +import com.openai.core.LONG +import com.openai.core.MAP +import com.openai.core.NULLABLE +import com.openai.core.NULLABLE_BOOLEAN +import com.openai.core.NULLABLE_DOUBLE +import com.openai.core.NULLABLE_LONG +import com.openai.core.OPTIONAL +import com.openai.core.SET +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorWriteFunctionsAreTested +import com.openai.core.checkOneDelegationWrite +import com.openai.core.findDelegationMethod +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.responseFormatFromClass +import com.openai.models.ChatModel +import com.openai.models.FunctionDefinition +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredChatCompletionCreateParams] class (delegator) and its delegation of + * most functions to a wrapped [ChatCompletionCreateParams] (delegate). It is the `Builder` class of + * each main class that is involved in the delegation. The tests include confirmation of the + * following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredChatCompletionCreateParamsTest { + companion object { + private val CHAT_MODEL = ChatModel.GPT_4 + + private val MESSAGE = + ChatCompletionMessage.builder().content(STRING).refusal(STRING).build() + + private val USER_MESSAGE_PARAM = + ChatCompletionUserMessageParam.builder().content(STRING).build() + private val DEV_MESSAGE_PARAM = + ChatCompletionDeveloperMessageParam.builder().content(STRING).build() + private val SYS_MESSAGE_PARAM = + ChatCompletionSystemMessageParam.builder().content(STRING).build() + private val ASSIST_MESSAGE_PARAM = + ChatCompletionAssistantMessageParam.builder().content(STRING).build() + private val TOOL_MESSAGE_PARAM = + ChatCompletionToolMessageParam.builder().content(STRING).toolCallId(STRING).build() + private val FUNC_MESSAGE_PARAM = + ChatCompletionFunctionMessageParam.builder().content(STRING).name(STRING).build() + private val MESSAGE_PARAM = ChatCompletionMessageParam.ofUser(USER_MESSAGE_PARAM) + + private val DEV_MESSAGE_PARAM_CONTENT = + ChatCompletionDeveloperMessageParam.Content.ofText(STRING) + private val SYS_MESSAGE_PARAM_CONTENT = + ChatCompletionSystemMessageParam.Content.ofText(STRING) + private val USER_MESSAGE_PARAM_CONTENT = + ChatCompletionUserMessageParam.Content.ofText(STRING) + + private val PARAMS_BODY = + ChatCompletionCreateParams.Body.builder() + .messages(listOf(MESSAGE_PARAM)) + .model(CHAT_MODEL) + .build() + private val WEB_SEARCH_OPTIONS = + ChatCompletionCreateParams.WebSearchOptions.builder().build() + + private val FUNCTION_CALL_MODE = + ChatCompletionCreateParams.FunctionCall.FunctionCallMode.AUTO + private val FUNCTION_CALL_OPTION = + ChatCompletionFunctionCallOption.builder().name(STRING).build() + private val FUNCTION_CALL = + ChatCompletionCreateParams.FunctionCall.ofFunctionCallOption(FUNCTION_CALL_OPTION) + + private val FUNCTION = ChatCompletionCreateParams.Function.builder().name(STRING).build() + private val METADATA = ChatCompletionCreateParams.Metadata.builder().build() + private val MODALITY = ChatCompletionCreateParams.Modality.TEXT + private val FUNCTION_DEFINITION = FunctionDefinition.builder().name(STRING).build() + private val TOOL = ChatCompletionTool.builder().function(FUNCTION_DEFINITION).build() + + private val NAMED_TOOL_CHOICE_FUNCTION = + ChatCompletionNamedToolChoice.Function.builder().name(STRING).build() + private val NAMED_TOOL_CHOICE = + ChatCompletionNamedToolChoice.builder().function(NAMED_TOOL_CHOICE_FUNCTION).build() + private val TOOL_CHOICE_OPTION_AUTO = ChatCompletionToolChoiceOption.Auto.AUTO + private val TOOL_CHOICE_OPTION = + ChatCompletionToolChoiceOption.ofAuto(TOOL_CHOICE_OPTION_AUTO) + + private val HEADERS = Headers.builder().build() + private val QUERY_PARAMS = QueryParams.builder().build() + + // The list order follows the declaration order in `ChatCompletionCreateParams.Builder` for + // easier maintenance. + @JvmStatic + private fun builderDelegationTestCases() = + listOf( + DelegationWriteTestCase("body", PARAMS_BODY), + DelegationWriteTestCase("messages", LIST), + DelegationWriteTestCase("messages", JSON_FIELD), + DelegationWriteTestCase("addMessage", MESSAGE_PARAM), + DelegationWriteTestCase("addMessage", DEV_MESSAGE_PARAM), + DelegationWriteTestCase("addDeveloperMessage", DEV_MESSAGE_PARAM_CONTENT), + DelegationWriteTestCase("addDeveloperMessage", STRING), + DelegationWriteTestCase("addDeveloperMessageOfArrayOfContentParts", LIST), + DelegationWriteTestCase("addMessage", SYS_MESSAGE_PARAM), + DelegationWriteTestCase("addSystemMessage", SYS_MESSAGE_PARAM_CONTENT), + DelegationWriteTestCase("addSystemMessage", STRING), + DelegationWriteTestCase("addSystemMessageOfArrayOfContentParts", LIST), + DelegationWriteTestCase("addMessage", USER_MESSAGE_PARAM), + DelegationWriteTestCase("addUserMessage", USER_MESSAGE_PARAM_CONTENT), + DelegationWriteTestCase("addUserMessage", STRING), + DelegationWriteTestCase("addUserMessageOfArrayOfContentParts", LIST), + DelegationWriteTestCase("addMessage", ASSIST_MESSAGE_PARAM), + DelegationWriteTestCase("addMessage", MESSAGE), + DelegationWriteTestCase("addMessage", TOOL_MESSAGE_PARAM), + DelegationWriteTestCase("addMessage", FUNC_MESSAGE_PARAM), + DelegationWriteTestCase("model", CHAT_MODEL), + DelegationWriteTestCase("model", JSON_FIELD), + DelegationWriteTestCase("model", STRING), + DelegationWriteTestCase("audio", NULLABLE), + DelegationWriteTestCase("audio", OPTIONAL), + DelegationWriteTestCase("audio", JSON_FIELD), + DelegationWriteTestCase("frequencyPenalty", NULLABLE_DOUBLE), + DelegationWriteTestCase("frequencyPenalty", DOUBLE), + DelegationWriteTestCase("frequencyPenalty", OPTIONAL), + DelegationWriteTestCase("frequencyPenalty", JSON_FIELD), + DelegationWriteTestCase("functionCall", FUNCTION_CALL), + DelegationWriteTestCase("functionCall", JSON_FIELD), + DelegationWriteTestCase("functionCall", FUNCTION_CALL_MODE), + DelegationWriteTestCase("functionCall", FUNCTION_CALL_OPTION), + DelegationWriteTestCase("functions", LIST), + DelegationWriteTestCase("functions", JSON_FIELD), + DelegationWriteTestCase("addFunction", FUNCTION), + DelegationWriteTestCase("logitBias", NULLABLE), + DelegationWriteTestCase("logitBias", OPTIONAL), + DelegationWriteTestCase("logitBias", JSON_FIELD), + DelegationWriteTestCase("logprobs", NULLABLE_BOOLEAN), + DelegationWriteTestCase("logprobs", BOOLEAN), + DelegationWriteTestCase("logprobs", OPTIONAL), + DelegationWriteTestCase("logprobs", JSON_FIELD), + DelegationWriteTestCase("maxCompletionTokens", NULLABLE_LONG), + DelegationWriteTestCase("maxCompletionTokens", LONG), + DelegationWriteTestCase("maxCompletionTokens", OPTIONAL), + DelegationWriteTestCase("maxCompletionTokens", JSON_FIELD), + DelegationWriteTestCase("maxTokens", NULLABLE_LONG), + DelegationWriteTestCase("maxTokens", LONG), + DelegationWriteTestCase("maxTokens", OPTIONAL), + DelegationWriteTestCase("maxTokens", JSON_FIELD), + DelegationWriteTestCase("metadata", METADATA), + DelegationWriteTestCase("metadata", OPTIONAL), + DelegationWriteTestCase("metadata", JSON_FIELD), + DelegationWriteTestCase("modalities", LIST), + DelegationWriteTestCase("modalities", OPTIONAL), + DelegationWriteTestCase("modalities", JSON_FIELD), + DelegationWriteTestCase("addModality", MODALITY), + DelegationWriteTestCase("n", NULLABLE_LONG), + DelegationWriteTestCase("n", LONG), + DelegationWriteTestCase("n", OPTIONAL), + DelegationWriteTestCase("n", JSON_FIELD), + DelegationWriteTestCase("parallelToolCalls", BOOLEAN), + DelegationWriteTestCase("parallelToolCalls", JSON_FIELD), + DelegationWriteTestCase("prediction", NULLABLE), + DelegationWriteTestCase("prediction", OPTIONAL), + DelegationWriteTestCase("prediction", JSON_FIELD), + DelegationWriteTestCase("presencePenalty", NULLABLE_DOUBLE), + DelegationWriteTestCase("presencePenalty", DOUBLE), + DelegationWriteTestCase("presencePenalty", OPTIONAL), + DelegationWriteTestCase("presencePenalty", JSON_FIELD), + DelegationWriteTestCase("reasoningEffort", NULLABLE), + DelegationWriteTestCase("reasoningEffort", OPTIONAL), + DelegationWriteTestCase("reasoningEffort", JSON_FIELD), + // `responseFormat()` is a special case and has its own unit test. + DelegationWriteTestCase("seed", NULLABLE_LONG), + DelegationWriteTestCase("seed", LONG), + DelegationWriteTestCase("seed", OPTIONAL), + DelegationWriteTestCase("seed", JSON_FIELD), + DelegationWriteTestCase("serviceTier", NULLABLE), + DelegationWriteTestCase("serviceTier", OPTIONAL), + DelegationWriteTestCase("serviceTier", JSON_FIELD), + DelegationWriteTestCase("stop", NULLABLE), + DelegationWriteTestCase("stop", OPTIONAL), + DelegationWriteTestCase("stop", JSON_FIELD), + DelegationWriteTestCase("stop", STRING), + DelegationWriteTestCase("stopOfStrings", LIST), + DelegationWriteTestCase("store", NULLABLE_BOOLEAN), + DelegationWriteTestCase("store", BOOLEAN), + DelegationWriteTestCase("store", OPTIONAL), + DelegationWriteTestCase("store", JSON_FIELD), + DelegationWriteTestCase("streamOptions", NULLABLE), + DelegationWriteTestCase("streamOptions", OPTIONAL), + DelegationWriteTestCase("streamOptions", JSON_FIELD), + DelegationWriteTestCase("temperature", NULLABLE_DOUBLE), + DelegationWriteTestCase("temperature", DOUBLE), + DelegationWriteTestCase("temperature", OPTIONAL), + DelegationWriteTestCase("temperature", JSON_FIELD), + DelegationWriteTestCase("toolChoice", TOOL_CHOICE_OPTION), + DelegationWriteTestCase("toolChoice", JSON_FIELD), + DelegationWriteTestCase("toolChoice", TOOL_CHOICE_OPTION_AUTO), + DelegationWriteTestCase("toolChoice", NAMED_TOOL_CHOICE), + DelegationWriteTestCase("tools", LIST), + DelegationWriteTestCase("tools", JSON_FIELD), + DelegationWriteTestCase("addTool", TOOL), + DelegationWriteTestCase("topLogprobs", NULLABLE_LONG), + DelegationWriteTestCase("topLogprobs", LONG), + DelegationWriteTestCase("topLogprobs", OPTIONAL), + DelegationWriteTestCase("topLogprobs", JSON_FIELD), + DelegationWriteTestCase("topP", NULLABLE_DOUBLE), + DelegationWriteTestCase("topP", DOUBLE), + DelegationWriteTestCase("topP", OPTIONAL), + DelegationWriteTestCase("topP", JSON_FIELD), + DelegationWriteTestCase("user", STRING), + DelegationWriteTestCase("user", JSON_FIELD), + DelegationWriteTestCase("webSearchOptions", WEB_SEARCH_OPTIONS), + DelegationWriteTestCase("webSearchOptions", JSON_FIELD), + DelegationWriteTestCase("additionalBodyProperties", MAP), + DelegationWriteTestCase("putAdditionalBodyProperty", STRING, JSON_VALUE), + DelegationWriteTestCase("putAllAdditionalBodyProperties", MAP), + DelegationWriteTestCase("removeAdditionalBodyProperty", STRING), + DelegationWriteTestCase("removeAllAdditionalBodyProperties", SET), + DelegationWriteTestCase("additionalHeaders", HEADERS), + DelegationWriteTestCase("additionalHeaders", MAP), + DelegationWriteTestCase("putAdditionalHeader", STRING, STRING), + DelegationWriteTestCase("putAdditionalHeaders", STRING, LIST), + DelegationWriteTestCase("putAllAdditionalHeaders", HEADERS), + DelegationWriteTestCase("putAllAdditionalHeaders", MAP), + DelegationWriteTestCase("replaceAdditionalHeaders", STRING, STRING), + DelegationWriteTestCase("replaceAdditionalHeaders", STRING, LIST), + DelegationWriteTestCase("replaceAllAdditionalHeaders", HEADERS), + DelegationWriteTestCase("replaceAllAdditionalHeaders", MAP), + DelegationWriteTestCase("removeAdditionalHeaders", STRING), + DelegationWriteTestCase("removeAllAdditionalHeaders", SET), + DelegationWriteTestCase("additionalQueryParams", QUERY_PARAMS), + DelegationWriteTestCase("additionalQueryParams", MAP), + DelegationWriteTestCase("putAdditionalQueryParam", STRING, STRING), + DelegationWriteTestCase("putAdditionalQueryParams", STRING, LIST), + DelegationWriteTestCase("putAllAdditionalQueryParams", QUERY_PARAMS), + DelegationWriteTestCase("putAllAdditionalQueryParams", MAP), + DelegationWriteTestCase("replaceAdditionalQueryParams", STRING, STRING), + DelegationWriteTestCase("replaceAdditionalQueryParams", STRING, LIST), + DelegationWriteTestCase("replaceAllAdditionalQueryParams", QUERY_PARAMS), + DelegationWriteTestCase("replaceAllAdditionalQueryParams", MAP), + DelegationWriteTestCase("removeAdditionalQueryParams", STRING), + DelegationWriteTestCase("removeAllAdditionalQueryParams", SET), + ) + } + + // New instances of the `mockBuilderDelegate` and `builderDelegator` are required for each test + // case (each test case runs in its own instance of the test class). + private val mockBuilderDelegate: ChatCompletionCreateParams.Builder = + mock(ChatCompletionCreateParams.Builder::class.java) + private val builderDelegator = + StructuredChatCompletionCreateParams.builder().inject(mockBuilderDelegate) + + @Test + fun allBuilderDelegateFunctionsExistInDelegator() { + // The delegator class does not implement the various `responseFormat` functions of the + // delegate class. + checkAllDelegation(mockBuilderDelegate::class, builderDelegator::class, "responseFormat") + } + + @Test + fun allBuilderDelegatorFunctionsExistInDelegate() { + // The delegator implements a different `responseFormat` function from those overloads in + // the delegate class. + checkAllDelegation(builderDelegator::class, mockBuilderDelegate::class, "responseFormat") + } + + @Test + fun allBuilderDelegatorFunctionsAreTested() { + checkAllDelegatorWriteFunctionsAreTested( + builderDelegator::class, + builderDelegationTestCases(), + exceptionalTestedFns = setOf("responseFormat"), + nonDelegatingFns = setOf("build", "wrap", "inject"), + ) + } + + @ParameterizedTest + @MethodSource("builderDelegationTestCases") + fun `delegation of Builder write functions`(testCase: DelegationWriteTestCase) { + checkOneDelegationWrite(builderDelegator, mockBuilderDelegate, testCase) + } + + @Test + fun `delegation of responseFormat`() { + // Special unit test case as the delegator method signature does not match that of the + // delegate method. + val delegatorTestCase = DelegationWriteTestCase("responseFormat", X::class.java) + val delegatorMethod = findDelegationMethod(builderDelegator, delegatorTestCase) + val mockDelegateTestCase = + DelegationWriteTestCase("responseFormat", responseFormatFromClass(X::class.java)) + val mockDelegateMethod = findDelegationMethod(mockBuilderDelegate, mockDelegateTestCase) + + delegatorMethod.invoke(builderDelegator, delegatorTestCase.inputValues[0]) + + // Verify that the corresponding method on the mock delegate was called exactly once. + verify(mockBuilderDelegate, times(1)).apply { + mockDelegateMethod.invoke(mockBuilderDelegate, mockDelegateTestCase.inputValues[0]) + } + verifyNoMoreInteractions(mockBuilderDelegate) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt new file mode 100644 index 000000000..939f9a538 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionMessageTest.kt @@ -0,0 +1,129 @@ +package com.openai.models.chat.completions + +import com.openai.core.DelegationReadTestCase +import com.openai.core.JSON_FIELD +import com.openai.core.JSON_VALUE +import com.openai.core.JsonField +import com.openai.core.OPTIONAL +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorReadFunctionsAreTested +import com.openai.core.checkOneDelegationRead +import java.util.Optional +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredChatCompletionMessage] class (delegator) and its delegation of most + * functions to a wrapped [ChatCompletionMessage] (delegate). The tests include confirmation of the + * following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredChatCompletionMessageTest { + companion object { + private val MESSAGE = + ChatCompletionMessage.builder().content(STRING).refusal(STRING).build() + + // The list order follows the declaration order in `ChatCompletionMessage` for easier + // maintenance. + @JvmStatic + private fun delegationTestCases() = + listOf( + // `content()` is a special case and has its own test function. + DelegationReadTestCase("refusal", OPTIONAL), + DelegationReadTestCase("_role", JSON_VALUE), + DelegationReadTestCase("annotations", OPTIONAL), + DelegationReadTestCase("audio", OPTIONAL), + DelegationReadTestCase("functionCall", OPTIONAL), + DelegationReadTestCase("toolCalls", OPTIONAL), + // `_content()` is a special case and has its own test function. + DelegationReadTestCase("_refusal", JSON_FIELD), + DelegationReadTestCase("_annotations", JSON_FIELD), + DelegationReadTestCase("_audio", JSON_FIELD), + DelegationReadTestCase("_functionCall", JSON_FIELD), + DelegationReadTestCase("_toolCalls", JSON_FIELD), + DelegationReadTestCase("_additionalProperties", mapOf("key" to JSON_VALUE)), + DelegationReadTestCase("validate", MESSAGE), + // For this boolean function, call with both possible values to ensure that any + // hard-coding or default value will not result in a false positive test. + DelegationReadTestCase("isValid", true), + DelegationReadTestCase("isValid", false), + ) + } + + // New instances of the `mockDelegate` and `delegator` are required for each test case (each + // test case runs in its own instance of the test class). + private val mockDelegate: ChatCompletionMessage = mock(ChatCompletionMessage::class.java) + private val delegator = StructuredChatCompletionMessage(X::class.java, mockDelegate) + + @Test + fun allDelegateFunctionsExistInDelegator() { + checkAllDelegation(mockDelegate::class, delegator::class, "toBuilder", "toParam") + } + + @Test + fun allDelegatorFunctionsExistInDelegate() { + checkAllDelegation(delegator::class, mockDelegate::class) + } + + @Test + fun allDelegatorFunctionsAreTested() { + // There are exceptional test cases for some functions. Most other functions are part of the + // list of those using the parameterized test. A few delegator functions do not delegate, so + // no test function is necessary. + checkAllDelegatorReadFunctionsAreTested( + delegator::class, + delegationTestCases(), + exceptionalTestedFns = setOf("content", "_content"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @ParameterizedTest + @MethodSource("delegationTestCases") + fun `delegation of functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(delegator, mockDelegate, testCase) + } + + @Test + fun `delegation of content`() { + // Input and output are different types, so this test is an exceptional case. + // `content()` (without an underscore) delegates to `_content()` (with an underscore) + // indirectly via the `content` field initializer. + val input = JsonField.of("{\"s\" : \"hello\"}") + `when`(mockDelegate._content()).thenReturn(input) + val output = delegator.content() // Without an underscore. + + verify(mockDelegate, times(1))._content() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output).isEqualTo(Optional.of(X("hello"))) + } + + @Test + fun `delegation of _content`() { + // Input and output are different types, so this test is an exceptional case. + // `_content()` delegates to `_content()` indirectly via the `content` field initializer. + val input = JsonField.of("{\"s\" : \"hello\"}") + `when`(mockDelegate._content()).thenReturn(input) + val output = delegator._content() // With an underscore. + + verify(mockDelegate, times(1))._content() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output).isEqualTo(JsonField.of(X("hello"))) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt new file mode 100644 index 000000000..40dc509f3 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/chat/completions/StructuredChatCompletionTest.kt @@ -0,0 +1,307 @@ +package com.openai.models.chat.completions + +import com.openai.core.DelegationReadTestCase +import com.openai.core.JSON_FIELD +import com.openai.core.JSON_VALUE +import com.openai.core.JsonField +import com.openai.core.LONG +import com.openai.core.OPTIONAL +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorReadFunctionsAreTested +import com.openai.core.checkOneDelegationRead +import com.openai.errors.OpenAIInvalidDataException +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredChatCompletion] class (delegator) and its delegation of most + * functions to a wrapped [ChatCompletion] (delegate). The tests include confirmation of the + * following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredChatCompletionTest { + companion object { + private val MESSAGE = + ChatCompletionMessage.builder().content(STRING).refusal(STRING).build() + private val FINISH_REASON = ChatCompletion.Choice.FinishReason.STOP + private val CHOICE = + ChatCompletion.Choice.builder() + .message(MESSAGE) + .index(0L) + .finishReason(FINISH_REASON) + .logprobs( + ChatCompletion.Choice.Logprobs.builder().content(null).refusal(null).build() + ) + .build() + + // The list order follows the declaration order in `ChatCompletion` for easier maintenance. + @JvmStatic + private fun delegationTestCases() = + listOf( + DelegationReadTestCase("id", STRING), + // `choices()` is a special case and has its own test function. + DelegationReadTestCase("created", LONG), + DelegationReadTestCase("model", STRING), + DelegationReadTestCase("_object_", JSON_VALUE), + DelegationReadTestCase("serviceTier", OPTIONAL), + DelegationReadTestCase("systemFingerprint", OPTIONAL), + DelegationReadTestCase("usage", OPTIONAL), + DelegationReadTestCase("_id", JSON_FIELD), + // `_choices()` is a special case and has its own test function. + DelegationReadTestCase("_created", JSON_FIELD), + DelegationReadTestCase("_model", JSON_FIELD), + DelegationReadTestCase("_serviceTier", JSON_FIELD), + DelegationReadTestCase("_systemFingerprint", JSON_FIELD), + DelegationReadTestCase("_usage", JSON_FIELD), + DelegationReadTestCase("_additionalProperties", mapOf("key" to JSON_VALUE)), + // `validate()` and `isValid()` (which calls `validate()`) are tested separately, + // as they require special handling. + ) + + @JvmStatic + private fun choiceDelegationTestCases() = + listOf( + DelegationReadTestCase("finishReason", FINISH_REASON), + DelegationReadTestCase("index", LONG), + DelegationReadTestCase("logprobs", OPTIONAL), + DelegationReadTestCase("_finishReason", JSON_FIELD), + // `message()` is a special case and has its own test function. + DelegationReadTestCase("_index", JSON_FIELD), + DelegationReadTestCase("_logprobs", JSON_FIELD), + // `_message()` is a special case and has its own test function. + DelegationReadTestCase("_additionalProperties", mapOf("key" to JSON_VALUE)), + // `validate()` and `isValid()` (which calls `validate()`) are tested separately, + // as they require special handling. + ) + } + + // New instances of the `mockDelegate` and `delegator` are required for each test case (each + // test case runs in its own instance of the test class). + private val mockDelegate: ChatCompletion = mock(ChatCompletion::class.java) + private val delegator = StructuredChatCompletion(X::class.java, mockDelegate) + + private val mockChoiceDelegate: ChatCompletion.Choice = mock(ChatCompletion.Choice::class.java) + private val choiceDelegator = + StructuredChatCompletion.Choice(X::class.java, mockChoiceDelegate) + + @Test + fun allChatCompletionDelegateFunctionsExistInDelegator() { + checkAllDelegation(mockDelegate::class, delegator::class, "toBuilder") + } + + @Test + fun allChatCompletionDelegatorFunctionsExistInDelegate() { + checkAllDelegation(delegator::class, mockDelegate::class) + } + + @Test + fun allChoiceDelegateFunctionsExistInDelegator() { + checkAllDelegation(mockChoiceDelegate::class, choiceDelegator::class, "toBuilder") + } + + @Test + fun allChoiceDelegatorFunctionsExistInDelegate() { + checkAllDelegation(choiceDelegator::class, mockChoiceDelegate::class) + } + + @Test + fun allDelegatorFunctionsAreTested() { + // There are exceptional test cases for some functions. Most other functions are part of the + // list of those using the parameterized test. A few delegator functions do not delegate, so + // no test function is necessary. + checkAllDelegatorReadFunctionsAreTested( + delegator::class, + delegationTestCases(), + exceptionalTestedFns = setOf("choices", "_choices", "validate", "isValid"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @Test + fun allChoiceDelegatorFunctionsAreTested() { + checkAllDelegatorReadFunctionsAreTested( + choiceDelegator::class, + choiceDelegationTestCases(), + exceptionalTestedFns = setOf("message", "_message", "validate", "isValid"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @ParameterizedTest + @MethodSource("delegationTestCases") + fun `delegation of functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(delegator, mockDelegate, testCase) + } + + @ParameterizedTest + @MethodSource("choiceDelegationTestCases") + fun `delegation of Choice functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(choiceDelegator, mockChoiceDelegate, testCase) + } + + @Test + fun `delegation of choices`() { + // Input and output are different types, so this test is an exceptional case. + // `choices()` (without an underscore) delegates to `_choices()` (with an underscore) + // indirectly via the `choices` field initializer. + val input = JsonField.of(listOf(CHOICE)) + `when`(mockDelegate._choices()).thenReturn(input) + val output = delegator.choices() // Without an underscore. + + verify(mockDelegate, times(1))._choices() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output[0].rawChoice).isEqualTo(CHOICE) + } + + @Test + fun `delegation of _choices`() { + // Input and output are different types, so this test is an exceptional case. + // `_choices()` delegates to `_choices()` indirectly via the `choices` field initializer. + val input = JsonField.of(listOf(CHOICE)) + `when`(mockDelegate._choices()).thenReturn(input) + val output = delegator._choices() // With an underscore. + + verify(mockDelegate, times(1))._choices() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output.getRequired("_choices")[0].rawChoice).isEqualTo(CHOICE) + } + + @Test + fun `delegation of validate`() { + val input = JsonField.of(listOf(CHOICE)) + `when`(mockDelegate._choices()).thenReturn(input) + val output = delegator.validate() + + // `validate()` calls `choices()` on the delegator which triggers the lazy initializer which + // calls `_choices()` on the delegate before `validate()` also calls `validate()` on the + // delegate. + verify(mockDelegate, times(1))._choices() + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output).isSameAs(delegator) + } + + @Test + fun `delegation of isValid when true`() { + val input = JsonField.of(listOf(CHOICE)) + `when`(mockDelegate._choices()).thenReturn(input) + val output = delegator.isValid() + + // `isValid()` calls `validate()`, which has side effects explained in its test function. + verify(mockDelegate, times(1))._choices() + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output).isTrue + } + + @Test + fun `delegation of isValid when false`() { + // Try with a `false` value to make sure `isValid()` is not just hard-coded to `true`. Do + // this by making `validate()` on the delegate throw an exception. + val input = JsonField.of(listOf(CHOICE)) + `when`(mockDelegate._choices()).thenReturn(input) + `when`(mockDelegate.validate()).thenThrow(OpenAIInvalidDataException("test")) + val output = delegator.isValid() + + // `isValid()` calls `validate()`, which has side effects explained in its test function. + verify(mockDelegate, times(1))._choices() + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output).isFalse + } + + @Test + fun `delegation of Choice-message`() { + // Input and output are different types, so this test is an exceptional case. + // `message()` (without an underscore) delegates to `_message()` (with an underscore) + // indirectly via the `message` field initializer. + val input = JsonField.of(MESSAGE) + `when`(mockChoiceDelegate._message()).thenReturn(input) + val output = choiceDelegator.message() // Without an underscore. + + verify(mockChoiceDelegate, times(1))._message() + verifyNoMoreInteractions(mockChoiceDelegate) + + assertThat(output.rawMessage).isEqualTo(MESSAGE) + } + + @Test + fun `delegation of Choice-_message`() { + // Input and output are different types, so this test is an exceptional case. + // `_message()` delegates to `_message()` indirectly via the `message` field initializer. + val input = JsonField.of(MESSAGE) + `when`(mockChoiceDelegate._message()).thenReturn(input) + val output = choiceDelegator._message() // With an underscore. + + verify(mockChoiceDelegate, times(1))._message() + verifyNoMoreInteractions(mockChoiceDelegate) + + assertThat(output.getRequired("_message").rawMessage).isEqualTo(MESSAGE) + } + + @Test + fun `delegation of Choice-validate`() { + val input = JsonField.of(MESSAGE) + `when`(mockChoiceDelegate._message()).thenReturn(input) + val output = choiceDelegator.validate() + + // `validate()` calls `message()` on the delegator which triggers the lazy initializer which + // calls `_message()` on the delegate before `validate()` also calls `validate()` on the + // delegate. + verify(mockChoiceDelegate, times(1))._message() + verify(mockChoiceDelegate, times(1)).validate() + verifyNoMoreInteractions(mockChoiceDelegate) + + assertThat(output).isSameAs(choiceDelegator) + } + + @Test + fun `delegation of Choice-isValid when true`() { + val input = JsonField.of(MESSAGE) + `when`(mockChoiceDelegate._message()).thenReturn(input) + val output = choiceDelegator.isValid() + + // `isValid()` calls `validate()`, which has side effects explained in its test function. + verify(mockChoiceDelegate, times(1))._message() + verify(mockChoiceDelegate, times(1)).validate() + verifyNoMoreInteractions(mockChoiceDelegate) + + assertThat(output).isTrue + } + + @Test + fun `delegation of Choice-isValid when false`() { + // Try with a `false` value to make sure `isValid()` is not just hard-coded to `true`. Do + // this by making `validate()` on the delegate throw an exception. + val input = JsonField.of(MESSAGE) + `when`(mockChoiceDelegate._message()).thenReturn(input) + `when`(mockChoiceDelegate.validate()).thenThrow(OpenAIInvalidDataException("test")) + val output = choiceDelegator.isValid() + + // `isValid()` calls `validate()`, which has side effects explained in its test function. + verify(mockChoiceDelegate, times(1))._message() + verify(mockChoiceDelegate, times(1)).validate() + verifyNoMoreInteractions(mockChoiceDelegate) + + assertThat(output).isFalse + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalCreateResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalCreateResponseTest.kt index 8d2a3a39a..208c7d652 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalCreateResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalCreateResponseTest.kt @@ -5,6 +5,7 @@ package com.openai.models.evals import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.LabelModelGrader import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -28,12 +29,12 @@ internal class EvalCreateResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -67,13 +68,13 @@ internal class EvalCreateResponseTest { assertThat(evalCreateResponse.name()).isEqualTo("Chatbot effectiveness Evaluation") assertThat(evalCreateResponse.testingCriteria()) .containsExactly( - EvalCreateResponse.TestingCriterion.ofLabelModel( - EvalLabelModelGrader.builder() + EvalCreateResponse.TestingCriterion.ofLabelModelGrader( + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -104,12 +105,12 @@ internal class EvalCreateResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalLabelModelGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalLabelModelGraderTest.kt deleted file mode 100644 index 06becabb8..000000000 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalLabelModelGraderTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.openai.models.evals - -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.openai.core.jsonMapper -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class EvalLabelModelGraderTest { - - @Test - fun create() { - val evalLabelModelGrader = - EvalLabelModelGrader.builder() - .addInput( - EvalLabelModelGrader.Input.builder() - .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) - .build() - ) - .addLabel("string") - .model("model") - .name("name") - .addPassingLabel("string") - .build() - - assertThat(evalLabelModelGrader.input()) - .containsExactly( - EvalLabelModelGrader.Input.builder() - .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) - .build() - ) - assertThat(evalLabelModelGrader.labels()).containsExactly("string") - assertThat(evalLabelModelGrader.model()).isEqualTo("model") - assertThat(evalLabelModelGrader.name()).isEqualTo("name") - assertThat(evalLabelModelGrader.passingLabels()).containsExactly("string") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val evalLabelModelGrader = - EvalLabelModelGrader.builder() - .addInput( - EvalLabelModelGrader.Input.builder() - .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) - .build() - ) - .addLabel("string") - .model("model") - .name("name") - .addPassingLabel("string") - .build() - - val roundtrippedEvalLabelModelGrader = - jsonMapper.readValue( - jsonMapper.writeValueAsString(evalLabelModelGrader), - jacksonTypeRef(), - ) - - assertThat(roundtrippedEvalLabelModelGrader).isEqualTo(evalLabelModelGrader) - } -} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListPageResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListPageResponseTest.kt index a063219ca..10d5eddbd 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListPageResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListPageResponseTest.kt @@ -5,6 +5,7 @@ package com.openai.models.evals import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.LabelModelGrader import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -30,12 +31,12 @@ internal class EvalListPageResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -68,12 +69,12 @@ internal class EvalListPageResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -110,12 +111,12 @@ internal class EvalListPageResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListResponseTest.kt index a88350116..11f418a8d 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalListResponseTest.kt @@ -5,6 +5,7 @@ package com.openai.models.evals import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.LabelModelGrader import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -28,12 +29,12 @@ internal class EvalListResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -67,13 +68,13 @@ internal class EvalListResponseTest { assertThat(evalListResponse.name()).isEqualTo("Chatbot effectiveness Evaluation") assertThat(evalListResponse.testingCriteria()) .containsExactly( - EvalListResponse.TestingCriterion.ofLabelModel( - EvalLabelModelGrader.builder() + EvalListResponse.TestingCriterion.ofLabelModelGrader( + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -104,12 +105,12 @@ internal class EvalListResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalRetrieveResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalRetrieveResponseTest.kt index dcf6e03c2..3838a4d01 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalRetrieveResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalRetrieveResponseTest.kt @@ -5,6 +5,7 @@ package com.openai.models.evals import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.LabelModelGrader import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -28,12 +29,12 @@ internal class EvalRetrieveResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -67,13 +68,13 @@ internal class EvalRetrieveResponseTest { assertThat(evalRetrieveResponse.name()).isEqualTo("Chatbot effectiveness Evaluation") assertThat(evalRetrieveResponse.testingCriteria()) .containsExactly( - EvalRetrieveResponse.TestingCriterion.ofLabelModel( - EvalLabelModelGrader.builder() + EvalRetrieveResponse.TestingCriterion.ofLabelModelGrader( + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -104,12 +105,12 @@ internal class EvalRetrieveResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalStringCheckGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalStringCheckGraderTest.kt deleted file mode 100644 index d15819ad3..000000000 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalStringCheckGraderTest.kt +++ /dev/null @@ -1,47 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.openai.models.evals - -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.openai.core.jsonMapper -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class EvalStringCheckGraderTest { - - @Test - fun create() { - val evalStringCheckGrader = - EvalStringCheckGrader.builder() - .input("input") - .name("name") - .operation(EvalStringCheckGrader.Operation.EQ) - .reference("reference") - .build() - - assertThat(evalStringCheckGrader.input()).isEqualTo("input") - assertThat(evalStringCheckGrader.name()).isEqualTo("name") - assertThat(evalStringCheckGrader.operation()).isEqualTo(EvalStringCheckGrader.Operation.EQ) - assertThat(evalStringCheckGrader.reference()).isEqualTo("reference") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val evalStringCheckGrader = - EvalStringCheckGrader.builder() - .input("input") - .name("name") - .operation(EvalStringCheckGrader.Operation.EQ) - .reference("reference") - .build() - - val roundtrippedEvalStringCheckGrader = - jsonMapper.readValue( - jsonMapper.writeValueAsString(evalStringCheckGrader), - jacksonTypeRef(), - ) - - assertThat(roundtrippedEvalStringCheckGrader).isEqualTo(evalStringCheckGrader) - } -} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalTextSimilarityGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalTextSimilarityGraderTest.kt deleted file mode 100644 index f7cc1230b..000000000 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalTextSimilarityGraderTest.kt +++ /dev/null @@ -1,51 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. - -package com.openai.models.evals - -import com.fasterxml.jackson.module.kotlin.jacksonTypeRef -import com.openai.core.jsonMapper -import org.assertj.core.api.Assertions.assertThat -import org.junit.jupiter.api.Test - -internal class EvalTextSimilarityGraderTest { - - @Test - fun create() { - val evalTextSimilarityGrader = - EvalTextSimilarityGrader.builder() - .evaluationMetric(EvalTextSimilarityGrader.EvaluationMetric.FUZZY_MATCH) - .input("input") - .passThreshold(0.0) - .reference("reference") - .name("name") - .build() - - assertThat(evalTextSimilarityGrader.evaluationMetric()) - .isEqualTo(EvalTextSimilarityGrader.EvaluationMetric.FUZZY_MATCH) - assertThat(evalTextSimilarityGrader.input()).isEqualTo("input") - assertThat(evalTextSimilarityGrader.passThreshold()).isEqualTo(0.0) - assertThat(evalTextSimilarityGrader.reference()).isEqualTo("reference") - assertThat(evalTextSimilarityGrader.name()).contains("name") - } - - @Test - fun roundtrip() { - val jsonMapper = jsonMapper() - val evalTextSimilarityGrader = - EvalTextSimilarityGrader.builder() - .evaluationMetric(EvalTextSimilarityGrader.EvaluationMetric.FUZZY_MATCH) - .input("input") - .passThreshold(0.0) - .reference("reference") - .name("name") - .build() - - val roundtrippedEvalTextSimilarityGrader = - jsonMapper.readValue( - jsonMapper.writeValueAsString(evalTextSimilarityGrader), - jacksonTypeRef(), - ) - - assertThat(roundtrippedEvalTextSimilarityGrader).isEqualTo(evalTextSimilarityGrader) - } -} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalUpdateResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalUpdateResponseTest.kt index 6a7d1e99f..e4632e7c0 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalUpdateResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/evals/EvalUpdateResponseTest.kt @@ -5,6 +5,7 @@ package com.openai.models.evals import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.LabelModelGrader import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -28,12 +29,12 @@ internal class EvalUpdateResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -67,13 +68,13 @@ internal class EvalUpdateResponseTest { assertThat(evalUpdateResponse.name()).isEqualTo("Chatbot effectiveness Evaluation") assertThat(evalUpdateResponse.testingCriteria()) .containsExactly( - EvalUpdateResponse.TestingCriterion.ofLabelModel( - EvalLabelModelGrader.builder() + EvalUpdateResponse.TestingCriterion.ofLabelModelGrader( + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") @@ -104,12 +105,12 @@ internal class EvalUpdateResponseTest { ) .name("Chatbot effectiveness Evaluation") .addTestingCriterion( - EvalLabelModelGrader.builder() + LabelModelGrader.builder() .addInput( - EvalLabelModelGrader.Input.builder() + LabelModelGrader.Input.builder() .content("string") - .role(EvalLabelModelGrader.Input.Role.USER) - .type(EvalLabelModelGrader.Input.Type.MESSAGE) + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) .build() ) .addLabel("string") diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunParamsTest.kt new file mode 100644 index 000000000..6054610f0 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunParamsTest.kt @@ -0,0 +1,60 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.openai.models.graders.gradermodels.StringCheckGrader +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GraderRunParamsTest { + + @Test + fun create() { + GraderRunParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .modelSample("model_sample") + .referenceAnswer("string") + .build() + } + + @Test + fun body() { + val params = + GraderRunParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .modelSample("model_sample") + .referenceAnswer("string") + .build() + + val body = params._body() + + assertThat(body.grader()) + .isEqualTo( + GraderRunParams.Grader.ofStringCheck( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + ) + assertThat(body.modelSample()).isEqualTo("model_sample") + assertThat(body.referenceAnswer()) + .isEqualTo(GraderRunParams.ReferenceAnswer.ofString("string")) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunResponseTest.kt new file mode 100644 index 000000000..ee806aba7 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderRunResponseTest.kt @@ -0,0 +1,172 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.JsonValue +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GraderRunResponseTest { + + @Test + fun create() { + val graderRunResponse = + GraderRunResponse.builder() + .metadata( + GraderRunResponse.Metadata.builder() + .errors( + GraderRunResponse.Metadata.Errors.builder() + .formulaParseError(true) + .invalidVariableError(true) + .modelGraderParseError(true) + .modelGraderRefusalError(true) + .modelGraderServerError(true) + .modelGraderServerErrorDetails("model_grader_server_error_details") + .otherError(true) + .pythonGraderRuntimeError(true) + .pythonGraderRuntimeErrorDetails( + "python_grader_runtime_error_details" + ) + .pythonGraderServerError(true) + .pythonGraderServerErrorType("python_grader_server_error_type") + .sampleParseError(true) + .truncatedObservationError(true) + .unresponsiveRewardError(true) + .build() + ) + .executionTime(0.0) + .name("name") + .sampledModelName("sampled_model_name") + .scores( + GraderRunResponse.Metadata.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .tokenUsage(0L) + .type("type") + .build() + ) + .modelGraderTokenUsagePerModel( + GraderRunResponse.ModelGraderTokenUsagePerModel.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .reward(0.0) + .subRewards( + GraderRunResponse.SubRewards.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + + assertThat(graderRunResponse.metadata()) + .isEqualTo( + GraderRunResponse.Metadata.builder() + .errors( + GraderRunResponse.Metadata.Errors.builder() + .formulaParseError(true) + .invalidVariableError(true) + .modelGraderParseError(true) + .modelGraderRefusalError(true) + .modelGraderServerError(true) + .modelGraderServerErrorDetails("model_grader_server_error_details") + .otherError(true) + .pythonGraderRuntimeError(true) + .pythonGraderRuntimeErrorDetails("python_grader_runtime_error_details") + .pythonGraderServerError(true) + .pythonGraderServerErrorType("python_grader_server_error_type") + .sampleParseError(true) + .truncatedObservationError(true) + .unresponsiveRewardError(true) + .build() + ) + .executionTime(0.0) + .name("name") + .sampledModelName("sampled_model_name") + .scores( + GraderRunResponse.Metadata.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .tokenUsage(0L) + .type("type") + .build() + ) + assertThat(graderRunResponse.modelGraderTokenUsagePerModel()) + .isEqualTo( + GraderRunResponse.ModelGraderTokenUsagePerModel.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + assertThat(graderRunResponse.reward()).isEqualTo(0.0) + assertThat(graderRunResponse.subRewards()) + .isEqualTo( + GraderRunResponse.SubRewards.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val graderRunResponse = + GraderRunResponse.builder() + .metadata( + GraderRunResponse.Metadata.builder() + .errors( + GraderRunResponse.Metadata.Errors.builder() + .formulaParseError(true) + .invalidVariableError(true) + .modelGraderParseError(true) + .modelGraderRefusalError(true) + .modelGraderServerError(true) + .modelGraderServerErrorDetails("model_grader_server_error_details") + .otherError(true) + .pythonGraderRuntimeError(true) + .pythonGraderRuntimeErrorDetails( + "python_grader_runtime_error_details" + ) + .pythonGraderServerError(true) + .pythonGraderServerErrorType("python_grader_server_error_type") + .sampleParseError(true) + .truncatedObservationError(true) + .unresponsiveRewardError(true) + .build() + ) + .executionTime(0.0) + .name("name") + .sampledModelName("sampled_model_name") + .scores( + GraderRunResponse.Metadata.Scores.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .tokenUsage(0L) + .type("type") + .build() + ) + .modelGraderTokenUsagePerModel( + GraderRunResponse.ModelGraderTokenUsagePerModel.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .reward(0.0) + .subRewards( + GraderRunResponse.SubRewards.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .build() + + val roundtrippedGraderRunResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(graderRunResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedGraderRunResponse).isEqualTo(graderRunResponse) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateParamsTest.kt new file mode 100644 index 000000000..214773004 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateParamsTest.kt @@ -0,0 +1,53 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.openai.models.graders.gradermodels.StringCheckGrader +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GraderValidateParamsTest { + + @Test + fun create() { + GraderValidateParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .build() + } + + @Test + fun body() { + val params = + GraderValidateParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .build() + + val body = params._body() + + assertThat(body.grader()) + .isEqualTo( + GraderValidateParams.Grader.ofStringCheck( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + ) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateResponseTest.kt new file mode 100644 index 000000000..7fc0a06d4 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/alpha/graders/GraderValidateResponseTest.kt @@ -0,0 +1,63 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.alpha.graders + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.StringCheckGrader +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class GraderValidateResponseTest { + + @Test + fun create() { + val graderValidateResponse = + GraderValidateResponse.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .build() + + assertThat(graderValidateResponse.grader()) + .contains( + GraderValidateResponse.Grader.ofStringCheck( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val graderValidateResponse = + GraderValidateResponse.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .build() + + val roundtrippedGraderValidateResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(graderValidateResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedGraderValidateResponse).isEqualTo(graderValidateResponse) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/FineTuningJobTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/FineTuningJobTest.kt index 33c530e68..5d1f8f919 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/FineTuningJobTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/FineTuningJobTest.kt @@ -5,6 +5,13 @@ package com.openai.models.finetuning.jobs import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.finetuning.methods.DpoHyperparameters +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementHyperparameters +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedHyperparameters +import com.openai.models.finetuning.methods.SupervisedMethod +import com.openai.models.graders.gradermodels.StringCheckGrader import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -61,10 +68,11 @@ internal class FineTuningJobTest { ) .method( FineTuningJob.Method.builder() + .type(FineTuningJob.Method.Type.SUPERVISED) .dpo( - FineTuningJob.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - FineTuningJob.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -73,10 +81,35 @@ internal class FineTuningJobTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - FineTuningJob.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - FineTuningJob.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -84,7 +117,6 @@ internal class FineTuningJobTest { ) .build() ) - .type(FineTuningJob.Method.Type.SUPERVISED) .build() ) .build() @@ -136,10 +168,11 @@ internal class FineTuningJobTest { assertThat(fineTuningJob.method()) .contains( FineTuningJob.Method.builder() + .type(FineTuningJob.Method.Type.SUPERVISED) .dpo( - FineTuningJob.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - FineTuningJob.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -148,10 +181,35 @@ internal class FineTuningJobTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - FineTuningJob.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - FineTuningJob.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -159,7 +217,6 @@ internal class FineTuningJobTest { ) .build() ) - .type(FineTuningJob.Method.Type.SUPERVISED) .build() ) } @@ -215,10 +272,11 @@ internal class FineTuningJobTest { ) .method( FineTuningJob.Method.builder() + .type(FineTuningJob.Method.Type.SUPERVISED) .dpo( - FineTuningJob.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - FineTuningJob.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -227,10 +285,35 @@ internal class FineTuningJobTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - FineTuningJob.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - FineTuningJob.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -238,7 +321,6 @@ internal class FineTuningJobTest { ) .build() ) - .type(FineTuningJob.Method.Type.SUPERVISED) .build() ) .build() diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobCreateParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobCreateParamsTest.kt index f3391493d..28cd1a8b2 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobCreateParamsTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobCreateParamsTest.kt @@ -3,6 +3,13 @@ package com.openai.models.finetuning.jobs import com.openai.core.JsonValue +import com.openai.models.finetuning.methods.DpoHyperparameters +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementHyperparameters +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedHyperparameters +import com.openai.models.finetuning.methods.SupervisedMethod +import com.openai.models.graders.gradermodels.StringCheckGrader import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -40,10 +47,11 @@ internal class JobCreateParamsTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -52,10 +60,35 @@ internal class JobCreateParamsTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -63,7 +96,6 @@ internal class JobCreateParamsTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -104,10 +136,11 @@ internal class JobCreateParamsTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -116,10 +149,35 @@ internal class JobCreateParamsTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -127,7 +185,6 @@ internal class JobCreateParamsTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -169,10 +226,11 @@ internal class JobCreateParamsTest { assertThat(body.method()) .contains( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -181,10 +239,35 @@ internal class JobCreateParamsTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -192,7 +275,6 @@ internal class JobCreateParamsTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) assertThat(body.seed()).contains(42L) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobListPageResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobListPageResponseTest.kt index 833580a8a..169aad89d 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobListPageResponseTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobListPageResponseTest.kt @@ -5,6 +5,13 @@ package com.openai.models.finetuning.jobs import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.openai.core.JsonValue import com.openai.core.jsonMapper +import com.openai.models.finetuning.methods.DpoHyperparameters +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementHyperparameters +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedHyperparameters +import com.openai.models.finetuning.methods.SupervisedMethod +import com.openai.models.graders.gradermodels.StringCheckGrader import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -62,10 +69,11 @@ internal class JobListPageResponseTest { ) .method( FineTuningJob.Method.builder() + .type(FineTuningJob.Method.Type.SUPERVISED) .dpo( - FineTuningJob.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - FineTuningJob.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -74,11 +82,36 @@ internal class JobListPageResponseTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - FineTuningJob.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - FineTuningJob.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -86,7 +119,6 @@ internal class JobListPageResponseTest { ) .build() ) - .type(FineTuningJob.Method.Type.SUPERVISED) .build() ) .build() @@ -143,10 +175,11 @@ internal class JobListPageResponseTest { ) .method( FineTuningJob.Method.builder() + .type(FineTuningJob.Method.Type.SUPERVISED) .dpo( - FineTuningJob.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - FineTuningJob.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -155,10 +188,35 @@ internal class JobListPageResponseTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - FineTuningJob.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - FineTuningJob.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -166,7 +224,6 @@ internal class JobListPageResponseTest { ) .build() ) - .type(FineTuningJob.Method.Type.SUPERVISED) .build() ) .build() @@ -227,10 +284,11 @@ internal class JobListPageResponseTest { ) .method( FineTuningJob.Method.builder() + .type(FineTuningJob.Method.Type.SUPERVISED) .dpo( - FineTuningJob.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - FineTuningJob.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -239,11 +297,36 @@ internal class JobListPageResponseTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - FineTuningJob.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - FineTuningJob.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -251,7 +334,6 @@ internal class JobListPageResponseTest { ) .build() ) - .type(FineTuningJob.Method.Type.SUPERVISED) .build() ) .build() diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobPauseParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobPauseParamsTest.kt new file mode 100644 index 000000000..052bab3e2 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobPauseParamsTest.kt @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.jobs + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class JobPauseParamsTest { + + @Test + fun create() { + JobPauseParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() + } + + @Test + fun pathParams() { + val params = JobPauseParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() + + assertThat(params._pathParam(0)).isEqualTo("ft-AF1WoRqd3aJAHsqc9NY7iL8F") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobResumeParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobResumeParamsTest.kt new file mode 100644 index 000000000..e3f90315e --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/jobs/JobResumeParamsTest.kt @@ -0,0 +1,24 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.jobs + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class JobResumeParamsTest { + + @Test + fun create() { + JobResumeParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() + } + + @Test + fun pathParams() { + val params = + JobResumeParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() + + assertThat(params._pathParam(0)).isEqualTo("ft-AF1WoRqd3aJAHsqc9NY7iL8F") + // out-of-bound path param + assertThat(params._pathParam(1)).isEqualTo("") + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/DpoHyperparametersTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/DpoHyperparametersTest.kt new file mode 100644 index 000000000..d220c3c7c --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/DpoHyperparametersTest.kt @@ -0,0 +1,48 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class DpoHyperparametersTest { + + @Test + fun create() { + val dpoHyperparameters = + DpoHyperparameters.builder() + .batchSizeAuto() + .betaAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + + assertThat(dpoHyperparameters.batchSize()).contains(DpoHyperparameters.BatchSize.ofAuto()) + assertThat(dpoHyperparameters.beta()).contains(DpoHyperparameters.Beta.ofAuto()) + assertThat(dpoHyperparameters.learningRateMultiplier()) + .contains(DpoHyperparameters.LearningRateMultiplier.ofAuto()) + assertThat(dpoHyperparameters.nEpochs()).contains(DpoHyperparameters.NEpochs.ofAuto()) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val dpoHyperparameters = + DpoHyperparameters.builder() + .batchSizeAuto() + .betaAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + + val roundtrippedDpoHyperparameters = + jsonMapper.readValue( + jsonMapper.writeValueAsString(dpoHyperparameters), + jacksonTypeRef(), + ) + + assertThat(roundtrippedDpoHyperparameters).isEqualTo(dpoHyperparameters) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/DpoMethodTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/DpoMethodTest.kt new file mode 100644 index 000000000..58ef87317 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/DpoMethodTest.kt @@ -0,0 +1,60 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class DpoMethodTest { + + @Test + fun create() { + val dpoMethod = + DpoMethod.builder() + .hyperparameters( + DpoHyperparameters.builder() + .batchSizeAuto() + .betaAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + ) + .build() + + assertThat(dpoMethod.hyperparameters()) + .contains( + DpoHyperparameters.builder() + .batchSizeAuto() + .betaAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val dpoMethod = + DpoMethod.builder() + .hyperparameters( + DpoHyperparameters.builder() + .batchSizeAuto() + .betaAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + ) + .build() + + val roundtrippedDpoMethod = + jsonMapper.readValue( + jsonMapper.writeValueAsString(dpoMethod), + jacksonTypeRef(), + ) + + assertThat(roundtrippedDpoMethod).isEqualTo(dpoMethod) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/ReinforcementHyperparametersTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/ReinforcementHyperparametersTest.kt new file mode 100644 index 000000000..c72042346 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/ReinforcementHyperparametersTest.kt @@ -0,0 +1,63 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ReinforcementHyperparametersTest { + + @Test + fun create() { + val reinforcementHyperparameters = + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort(ReinforcementHyperparameters.ReasoningEffort.DEFAULT) + .build() + + assertThat(reinforcementHyperparameters.batchSize()) + .contains(ReinforcementHyperparameters.BatchSize.ofAuto()) + assertThat(reinforcementHyperparameters.computeMultiplier()) + .contains(ReinforcementHyperparameters.ComputeMultiplier.ofAuto()) + assertThat(reinforcementHyperparameters.evalInterval()) + .contains(ReinforcementHyperparameters.EvalInterval.ofAuto()) + assertThat(reinforcementHyperparameters.evalSamples()) + .contains(ReinforcementHyperparameters.EvalSamples.ofAuto()) + assertThat(reinforcementHyperparameters.learningRateMultiplier()) + .contains(ReinforcementHyperparameters.LearningRateMultiplier.ofAuto()) + assertThat(reinforcementHyperparameters.nEpochs()) + .contains(ReinforcementHyperparameters.NEpochs.ofAuto()) + assertThat(reinforcementHyperparameters.reasoningEffort()) + .contains(ReinforcementHyperparameters.ReasoningEffort.DEFAULT) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val reinforcementHyperparameters = + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort(ReinforcementHyperparameters.ReasoningEffort.DEFAULT) + .build() + + val roundtrippedReinforcementHyperparameters = + jsonMapper.readValue( + jsonMapper.writeValueAsString(reinforcementHyperparameters), + jacksonTypeRef(), + ) + + assertThat(roundtrippedReinforcementHyperparameters).isEqualTo(reinforcementHyperparameters) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/ReinforcementMethodTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/ReinforcementMethodTest.kt new file mode 100644 index 000000000..271a02bee --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/ReinforcementMethodTest.kt @@ -0,0 +1,97 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import com.openai.models.graders.gradermodels.StringCheckGrader +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ReinforcementMethodTest { + + @Test + fun create() { + val reinforcementMethod = + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort(ReinforcementHyperparameters.ReasoningEffort.DEFAULT) + .build() + ) + .build() + + assertThat(reinforcementMethod.grader()) + .isEqualTo( + ReinforcementMethod.Grader.ofStringCheck( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + ) + assertThat(reinforcementMethod.hyperparameters()) + .contains( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort(ReinforcementHyperparameters.ReasoningEffort.DEFAULT) + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val reinforcementMethod = + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort(ReinforcementHyperparameters.ReasoningEffort.DEFAULT) + .build() + ) + .build() + + val roundtrippedReinforcementMethod = + jsonMapper.readValue( + jsonMapper.writeValueAsString(reinforcementMethod), + jacksonTypeRef(), + ) + + assertThat(roundtrippedReinforcementMethod).isEqualTo(reinforcementMethod) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/SupervisedHyperparametersTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/SupervisedHyperparametersTest.kt new file mode 100644 index 000000000..99b9ec04d --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/SupervisedHyperparametersTest.kt @@ -0,0 +1,47 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SupervisedHyperparametersTest { + + @Test + fun create() { + val supervisedHyperparameters = + SupervisedHyperparameters.builder() + .batchSizeAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + + assertThat(supervisedHyperparameters.batchSize()) + .contains(SupervisedHyperparameters.BatchSize.ofAuto()) + assertThat(supervisedHyperparameters.learningRateMultiplier()) + .contains(SupervisedHyperparameters.LearningRateMultiplier.ofAuto()) + assertThat(supervisedHyperparameters.nEpochs()) + .contains(SupervisedHyperparameters.NEpochs.ofAuto()) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val supervisedHyperparameters = + SupervisedHyperparameters.builder() + .batchSizeAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + + val roundtrippedSupervisedHyperparameters = + jsonMapper.readValue( + jsonMapper.writeValueAsString(supervisedHyperparameters), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSupervisedHyperparameters).isEqualTo(supervisedHyperparameters) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/SupervisedMethodTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/SupervisedMethodTest.kt new file mode 100644 index 000000000..93769d44f --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/finetuning/methods/SupervisedMethodTest.kt @@ -0,0 +1,57 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.finetuning.methods + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class SupervisedMethodTest { + + @Test + fun create() { + val supervisedMethod = + SupervisedMethod.builder() + .hyperparameters( + SupervisedHyperparameters.builder() + .batchSizeAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + ) + .build() + + assertThat(supervisedMethod.hyperparameters()) + .contains( + SupervisedHyperparameters.builder() + .batchSizeAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val supervisedMethod = + SupervisedMethod.builder() + .hyperparameters( + SupervisedHyperparameters.builder() + .batchSizeAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .build() + ) + .build() + + val roundtrippedSupervisedMethod = + jsonMapper.readValue( + jsonMapper.writeValueAsString(supervisedMethod), + jacksonTypeRef(), + ) + + assertThat(roundtrippedSupervisedMethod).isEqualTo(supervisedMethod) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/LabelModelGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/LabelModelGraderTest.kt new file mode 100644 index 000000000..8243d7362 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/LabelModelGraderTest.kt @@ -0,0 +1,69 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class LabelModelGraderTest { + + @Test + fun create() { + val labelModelGrader = + LabelModelGrader.builder() + .addInput( + LabelModelGrader.Input.builder() + .content("string") + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) + .build() + ) + .addLabel("string") + .model("model") + .name("name") + .addPassingLabel("string") + .build() + + assertThat(labelModelGrader.input()) + .containsExactly( + LabelModelGrader.Input.builder() + .content("string") + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) + .build() + ) + assertThat(labelModelGrader.labels()).containsExactly("string") + assertThat(labelModelGrader.model()).isEqualTo("model") + assertThat(labelModelGrader.name()).isEqualTo("name") + assertThat(labelModelGrader.passingLabels()).containsExactly("string") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val labelModelGrader = + LabelModelGrader.builder() + .addInput( + LabelModelGrader.Input.builder() + .content("string") + .role(LabelModelGrader.Input.Role.USER) + .type(LabelModelGrader.Input.Type.MESSAGE) + .build() + ) + .addLabel("string") + .model("model") + .name("name") + .addPassingLabel("string") + .build() + + val roundtrippedLabelModelGrader = + jsonMapper.readValue( + jsonMapper.writeValueAsString(labelModelGrader), + jacksonTypeRef(), + ) + + assertThat(roundtrippedLabelModelGrader).isEqualTo(labelModelGrader) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/MultiGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/MultiGraderTest.kt new file mode 100644 index 000000000..81423d030 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/MultiGraderTest.kt @@ -0,0 +1,91 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.JsonValue +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class MultiGraderTest { + + @Test + fun create() { + val multiGrader = + MultiGrader.builder() + .calculateOutput("calculate_output") + .graders( + MultiGrader.Graders.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "input" to "input", + "name" to "name", + "operation" to "eq", + "reference" to "reference", + "type" to "string_check", + ) + ), + ) + .build() + ) + .name("name") + .build() + + assertThat(multiGrader.calculateOutput()).isEqualTo("calculate_output") + assertThat(multiGrader.graders()) + .isEqualTo( + MultiGrader.Graders.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "input" to "input", + "name" to "name", + "operation" to "eq", + "reference" to "reference", + "type" to "string_check", + ) + ), + ) + .build() + ) + assertThat(multiGrader.name()).isEqualTo("name") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val multiGrader = + MultiGrader.builder() + .calculateOutput("calculate_output") + .graders( + MultiGrader.Graders.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "input" to "input", + "name" to "name", + "operation" to "eq", + "reference" to "reference", + "type" to "string_check", + ) + ), + ) + .build() + ) + .name("name") + .build() + + val roundtrippedMultiGrader = + jsonMapper.readValue( + jsonMapper.writeValueAsString(multiGrader), + jacksonTypeRef(), + ) + + assertThat(roundtrippedMultiGrader).isEqualTo(multiGrader) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/PythonGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/PythonGraderTest.kt new file mode 100644 index 000000000..3ac30afbc --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/PythonGraderTest.kt @@ -0,0 +1,36 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class PythonGraderTest { + + @Test + fun create() { + val pythonGrader = + PythonGrader.builder().name("name").source("source").imageTag("image_tag").build() + + assertThat(pythonGrader.name()).isEqualTo("name") + assertThat(pythonGrader.source()).isEqualTo("source") + assertThat(pythonGrader.imageTag()).contains("image_tag") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val pythonGrader = + PythonGrader.builder().name("name").source("source").imageTag("image_tag").build() + + val roundtrippedPythonGrader = + jsonMapper.readValue( + jsonMapper.writeValueAsString(pythonGrader), + jacksonTypeRef(), + ) + + assertThat(roundtrippedPythonGrader).isEqualTo(pythonGrader) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/ScoreModelGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/ScoreModelGraderTest.kt new file mode 100644 index 000000000..ff2134b6f --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/ScoreModelGraderTest.kt @@ -0,0 +1,72 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.JsonValue +import com.openai.core.jsonMapper +import kotlin.jvm.optionals.getOrNull +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class ScoreModelGraderTest { + + @Test + fun create() { + val scoreModelGrader = + ScoreModelGrader.builder() + .addInput( + ScoreModelGrader.Input.builder() + .content("string") + .role(ScoreModelGrader.Input.Role.USER) + .type(ScoreModelGrader.Input.Type.MESSAGE) + .build() + ) + .model("model") + .name("name") + .addRange(0.0) + .samplingParams(JsonValue.from(mapOf())) + .build() + + assertThat(scoreModelGrader.input()) + .containsExactly( + ScoreModelGrader.Input.builder() + .content("string") + .role(ScoreModelGrader.Input.Role.USER) + .type(ScoreModelGrader.Input.Type.MESSAGE) + .build() + ) + assertThat(scoreModelGrader.model()).isEqualTo("model") + assertThat(scoreModelGrader.name()).isEqualTo("name") + assertThat(scoreModelGrader.range().getOrNull()).containsExactly(0.0) + assertThat(scoreModelGrader._samplingParams()) + .isEqualTo(JsonValue.from(mapOf())) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val scoreModelGrader = + ScoreModelGrader.builder() + .addInput( + ScoreModelGrader.Input.builder() + .content("string") + .role(ScoreModelGrader.Input.Role.USER) + .type(ScoreModelGrader.Input.Type.MESSAGE) + .build() + ) + .model("model") + .name("name") + .addRange(0.0) + .samplingParams(JsonValue.from(mapOf())) + .build() + + val roundtrippedScoreModelGrader = + jsonMapper.readValue( + jsonMapper.writeValueAsString(scoreModelGrader), + jacksonTypeRef(), + ) + + assertThat(roundtrippedScoreModelGrader).isEqualTo(scoreModelGrader) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/StringCheckGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/StringCheckGraderTest.kt new file mode 100644 index 000000000..6eb0c92b9 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/StringCheckGraderTest.kt @@ -0,0 +1,47 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class StringCheckGraderTest { + + @Test + fun create() { + val stringCheckGrader = + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + + assertThat(stringCheckGrader.input()).isEqualTo("input") + assertThat(stringCheckGrader.name()).isEqualTo("name") + assertThat(stringCheckGrader.operation()).isEqualTo(StringCheckGrader.Operation.EQ) + assertThat(stringCheckGrader.reference()).isEqualTo("reference") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val stringCheckGrader = + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + + val roundtrippedStringCheckGrader = + jsonMapper.readValue( + jsonMapper.writeValueAsString(stringCheckGrader), + jacksonTypeRef(), + ) + + assertThat(roundtrippedStringCheckGrader).isEqualTo(stringCheckGrader) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/TextSimilarityGraderTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/TextSimilarityGraderTest.kt new file mode 100644 index 000000000..f271eeb4f --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/graders/gradermodels/TextSimilarityGraderTest.kt @@ -0,0 +1,48 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.models.graders.gradermodels + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.openai.core.jsonMapper +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class TextSimilarityGraderTest { + + @Test + fun create() { + val textSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(TextSimilarityGrader.EvaluationMetric.FUZZY_MATCH) + .input("input") + .name("name") + .reference("reference") + .build() + + assertThat(textSimilarityGrader.evaluationMetric()) + .isEqualTo(TextSimilarityGrader.EvaluationMetric.FUZZY_MATCH) + assertThat(textSimilarityGrader.input()).isEqualTo("input") + assertThat(textSimilarityGrader.name()).isEqualTo("name") + assertThat(textSimilarityGrader.reference()).isEqualTo("reference") + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val textSimilarityGrader = + TextSimilarityGrader.builder() + .evaluationMetric(TextSimilarityGrader.EvaluationMetric.FUZZY_MATCH) + .input("input") + .name("name") + .reference("reference") + .build() + + val roundtrippedTextSimilarityGrader = + jsonMapper.readValue( + jsonMapper.writeValueAsString(textSimilarityGrader), + jacksonTypeRef(), + ) + + assertThat(roundtrippedTextSimilarityGrader).isEqualTo(textSimilarityGrader) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFileSearchToolCallTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFileSearchToolCallTest.kt index 50752fd39..414ef927c 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFileSearchToolCallTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseFileSearchToolCallTest.kt @@ -27,7 +27,7 @@ internal class ResponseFileSearchToolCallTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) @@ -47,7 +47,7 @@ internal class ResponseFileSearchToolCallTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) @@ -70,7 +70,7 @@ internal class ResponseFileSearchToolCallTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseInputItemTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseInputItemTest.kt index 4ca8296c1..875e90e4f 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseInputItemTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseInputItemTest.kt @@ -187,7 +187,7 @@ internal class ResponseInputItemTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) @@ -226,7 +226,7 @@ internal class ResponseInputItemTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseItemTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseItemTest.kt index 2e4bfed33..2f3896e89 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseItemTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseItemTest.kt @@ -138,7 +138,7 @@ internal class ResponseItemTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) @@ -174,7 +174,7 @@ internal class ResponseItemTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseOutputItemTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseOutputItemTest.kt index 763f097af..66edbe7df 100644 --- a/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseOutputItemTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/ResponseOutputItemTest.kt @@ -90,7 +90,7 @@ internal class ResponseOutputItemTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) @@ -124,7 +124,7 @@ internal class ResponseOutputItemTest { ) .fileId("file_id") .filename("filename") - .score(0.0) + .score(0.0f) .text("text") .build() ) diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt new file mode 100644 index 000000000..3d2050729 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseCreateParamsTest.kt @@ -0,0 +1,243 @@ +package com.openai.models.responses + +import com.openai.core.BOOLEAN +import com.openai.core.DOUBLE +import com.openai.core.DelegationWriteTestCase +import com.openai.core.JSON_FIELD +import com.openai.core.JSON_VALUE +import com.openai.core.LIST +import com.openai.core.LONG +import com.openai.core.MAP +import com.openai.core.NULLABLE +import com.openai.core.NULLABLE_BOOLEAN +import com.openai.core.NULLABLE_DOUBLE +import com.openai.core.NULLABLE_LONG +import com.openai.core.NULLABLE_STRING +import com.openai.core.OPTIONAL +import com.openai.core.SET +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorWriteFunctionsAreTested +import com.openai.core.checkOneDelegationWrite +import com.openai.core.findDelegationMethod +import com.openai.core.http.Headers +import com.openai.core.http.QueryParams +import com.openai.core.textConfigFromClass +import com.openai.models.ChatModel +import com.openai.models.Reasoning +import com.openai.models.ResponsesModel +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredResponseCreateParams] class (delegator) and its delegation of most + * functions to a wrapped [ResponseCreateParams] (delegate). The tests include confirmation of the + * following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredResponseCreateParamsTest { + companion object { + private val CHAT_MODEL = ChatModel.GPT_4O + private val RESPONSES_MODEL = ResponsesModel.ofChat(CHAT_MODEL) + private val RESPONSES_ONLY_MODEL = ResponsesModel.ResponsesOnlyModel.O1_PRO + private val PARAMS_INPUT = ResponseCreateParams.Input.ofText(STRING) + + private val INCLUDABLE = ResponseIncludable.of(STRING) + private val METADATA = ResponseCreateParams.Metadata.builder().build() + private val SERVICE_TIER = ResponseCreateParams.ServiceTier.AUTO + private val REASONING = Reasoning.builder().build() + + private val TOOL_CHOICE_TYPE = ToolChoiceTypes.Type.FILE_SEARCH + private val TOOL_CHOICE_TYPES = ToolChoiceTypes.builder().type(TOOL_CHOICE_TYPE).build() + private val TOOL_CHOICE = ResponseCreateParams.ToolChoice.ofTypes(TOOL_CHOICE_TYPES) + private val TOOL_CHOICE_OPTIONS = ToolChoiceOptions.AUTO + private val TOOL_CHOICE_FUNCTION = ToolChoiceFunction.builder().name(STRING).build() + + private val FUNCTION_TOOL = + FunctionTool.builder().name(STRING).parameters(NULLABLE).strict(BOOLEAN).build() + private val FILE_SEARCH_TOOL = FileSearchTool.builder().vectorStoreIds(LIST).build() + private val WEB_SEARCH_TOOL = + WebSearchTool.builder().type(WebSearchTool.Type.WEB_SEARCH_PREVIEW).build() + private val COMPUTER_TOOL = + ComputerTool.builder() + .displayWidth(LONG) + .displayHeight(LONG) + .environment(ComputerTool.Environment.LINUX) + .build() + private val TOOL = Tool.ofFunction(FUNCTION_TOOL) + + private val HEADERS = Headers.builder().build() + private val QUERY_PARAMS = QueryParams.builder().build() + + // The list order follows the declaration order in `ResponseCreateParams.Builder` for + // easier maintenance. + @JvmStatic + private fun builderDelegationTestCases() = + listOf( + // The `body(...)` function is deliberately not supported: too messy. + DelegationWriteTestCase("input", PARAMS_INPUT), + DelegationWriteTestCase("input", JSON_FIELD), + DelegationWriteTestCase("input", STRING), + DelegationWriteTestCase("inputOfResponse", LIST), + DelegationWriteTestCase("model", RESPONSES_MODEL), + DelegationWriteTestCase("model", JSON_FIELD), + DelegationWriteTestCase("model", STRING), + DelegationWriteTestCase("model", CHAT_MODEL), + DelegationWriteTestCase("model", RESPONSES_ONLY_MODEL), + DelegationWriteTestCase("include", LIST), + DelegationWriteTestCase("include", OPTIONAL), + DelegationWriteTestCase("include", JSON_FIELD), + DelegationWriteTestCase("addInclude", INCLUDABLE), + DelegationWriteTestCase("instructions", NULLABLE_STRING), + DelegationWriteTestCase("instructions", OPTIONAL), + DelegationWriteTestCase("instructions", JSON_FIELD), + DelegationWriteTestCase("maxOutputTokens", NULLABLE_LONG), + DelegationWriteTestCase("maxOutputTokens", LONG), + DelegationWriteTestCase("maxOutputTokens", OPTIONAL), + DelegationWriteTestCase("maxOutputTokens", JSON_FIELD), + DelegationWriteTestCase("metadata", METADATA), + DelegationWriteTestCase("metadata", OPTIONAL), + DelegationWriteTestCase("metadata", JSON_FIELD), + DelegationWriteTestCase("parallelToolCalls", NULLABLE_BOOLEAN), + DelegationWriteTestCase("parallelToolCalls", BOOLEAN), + DelegationWriteTestCase("parallelToolCalls", OPTIONAL), + DelegationWriteTestCase("parallelToolCalls", JSON_FIELD), + DelegationWriteTestCase("previousResponseId", NULLABLE_STRING), + DelegationWriteTestCase("previousResponseId", OPTIONAL), + DelegationWriteTestCase("previousResponseId", JSON_FIELD), + DelegationWriteTestCase("reasoning", REASONING), + DelegationWriteTestCase("reasoning", OPTIONAL), + DelegationWriteTestCase("reasoning", JSON_FIELD), + DelegationWriteTestCase("serviceTier", SERVICE_TIER), + DelegationWriteTestCase("serviceTier", OPTIONAL), + DelegationWriteTestCase("serviceTier", JSON_FIELD), + DelegationWriteTestCase("store", NULLABLE_BOOLEAN), + DelegationWriteTestCase("store", BOOLEAN), + DelegationWriteTestCase("store", OPTIONAL), + DelegationWriteTestCase("store", JSON_FIELD), + DelegationWriteTestCase("temperature", NULLABLE_DOUBLE), + DelegationWriteTestCase("temperature", DOUBLE), + DelegationWriteTestCase("temperature", OPTIONAL), + DelegationWriteTestCase("temperature", JSON_FIELD), + // `text()` is a special case and has its own unit tests. + DelegationWriteTestCase("toolChoice", TOOL_CHOICE), + DelegationWriteTestCase("toolChoice", JSON_FIELD), + DelegationWriteTestCase("toolChoice", TOOL_CHOICE_OPTIONS), + DelegationWriteTestCase("toolChoice", TOOL_CHOICE_TYPES), + DelegationWriteTestCase("toolChoice", TOOL_CHOICE_FUNCTION), + DelegationWriteTestCase("tools", LIST), + DelegationWriteTestCase("tools", JSON_FIELD), + DelegationWriteTestCase("addTool", TOOL), + DelegationWriteTestCase("addTool", FILE_SEARCH_TOOL), + DelegationWriteTestCase("addFileSearchTool", LIST), + DelegationWriteTestCase("addTool", FUNCTION_TOOL), + DelegationWriteTestCase("addTool", WEB_SEARCH_TOOL), + DelegationWriteTestCase("addTool", COMPUTER_TOOL), + DelegationWriteTestCase("topP", NULLABLE_DOUBLE), + DelegationWriteTestCase("topP", DOUBLE), + DelegationWriteTestCase("topP", OPTIONAL), + DelegationWriteTestCase("topP", JSON_FIELD), + DelegationWriteTestCase("truncation", NULLABLE), + DelegationWriteTestCase("truncation", OPTIONAL), + DelegationWriteTestCase("truncation", JSON_FIELD), + DelegationWriteTestCase("user", STRING), + DelegationWriteTestCase("user", JSON_FIELD), + DelegationWriteTestCase("additionalBodyProperties", MAP), + DelegationWriteTestCase("putAdditionalBodyProperty", STRING, JSON_VALUE), + DelegationWriteTestCase("putAllAdditionalBodyProperties", MAP), + DelegationWriteTestCase("removeAdditionalBodyProperty", STRING), + DelegationWriteTestCase("removeAllAdditionalBodyProperties", SET), + DelegationWriteTestCase("additionalHeaders", HEADERS), + DelegationWriteTestCase("additionalHeaders", MAP), + DelegationWriteTestCase("putAdditionalHeader", STRING, STRING), + DelegationWriteTestCase("putAdditionalHeaders", STRING, LIST), + DelegationWriteTestCase("putAllAdditionalHeaders", HEADERS), + DelegationWriteTestCase("putAllAdditionalHeaders", MAP), + DelegationWriteTestCase("replaceAdditionalHeaders", STRING, STRING), + DelegationWriteTestCase("replaceAdditionalHeaders", STRING, LIST), + DelegationWriteTestCase("replaceAllAdditionalHeaders", HEADERS), + DelegationWriteTestCase("replaceAllAdditionalHeaders", MAP), + DelegationWriteTestCase("removeAdditionalHeaders", STRING), + DelegationWriteTestCase("removeAllAdditionalHeaders", SET), + DelegationWriteTestCase("additionalQueryParams", QUERY_PARAMS), + DelegationWriteTestCase("additionalQueryParams", MAP), + DelegationWriteTestCase("putAdditionalQueryParam", STRING, STRING), + DelegationWriteTestCase("putAdditionalQueryParams", STRING, LIST), + DelegationWriteTestCase("putAllAdditionalQueryParams", QUERY_PARAMS), + DelegationWriteTestCase("putAllAdditionalQueryParams", MAP), + DelegationWriteTestCase("replaceAdditionalQueryParams", STRING, STRING), + DelegationWriteTestCase("replaceAdditionalQueryParams", STRING, LIST), + DelegationWriteTestCase("replaceAllAdditionalQueryParams", QUERY_PARAMS), + DelegationWriteTestCase("replaceAllAdditionalQueryParams", MAP), + DelegationWriteTestCase("removeAdditionalQueryParams", STRING), + DelegationWriteTestCase("removeAllAdditionalQueryParams", SET), + ) + } + + // New instances of the `mockBuilderDelegate` and `builderDelegator` are required for each test + // case (each test case runs in its own instance of the test class). + private val mockBuilderDelegate: ResponseCreateParams.Builder = + mock(ResponseCreateParams.Builder::class.java) + private val builderDelegator = + StructuredResponseCreateParams.builder().inject(mockBuilderDelegate) + + @Test + fun allBuilderDelegateFunctionsExistInDelegator() { + // The delegator class does not implement the various `text` functions or the `body` + // function of the delegate class. + checkAllDelegation(mockBuilderDelegate::class, builderDelegator::class, "body", "text") + } + + @Test + fun allBuilderDelegatorFunctionsExistInDelegate() { + // The delegator implements a different `text` function from those overloads in the delegate + // class. + checkAllDelegation(builderDelegator::class, mockBuilderDelegate::class, "text") + } + + @Test + fun allBuilderDelegatorFunctionsAreTested() { + checkAllDelegatorWriteFunctionsAreTested( + builderDelegator::class, + builderDelegationTestCases(), + exceptionalTestedFns = setOf("text"), + nonDelegatingFns = setOf("build", "wrap", "inject"), + ) + } + + @ParameterizedTest + @MethodSource("builderDelegationTestCases") + fun `delegation of Builder write functions`(testCase: DelegationWriteTestCase) { + checkOneDelegationWrite(builderDelegator, mockBuilderDelegate, testCase) + } + + @Test + fun `delegation of text`() { + // Special unit test case as the delegator method signature does not match that of the + // delegate method. + val delegatorTestCase = DelegationWriteTestCase("text", X::class.java) + val delegatorMethod = findDelegationMethod(builderDelegator, delegatorTestCase) + val mockDelegateTestCase = + DelegationWriteTestCase("text", textConfigFromClass(X::class.java)) + val mockDelegateMethod = findDelegationMethod(mockBuilderDelegate, mockDelegateTestCase) + + delegatorMethod.invoke(builderDelegator, delegatorTestCase.inputValues[0]) + + // Verify that the corresponding method on the mock delegate was called exactly once. + verify(mockBuilderDelegate, times(1)).apply { + mockDelegateMethod.invoke(mockBuilderDelegate, mockDelegateTestCase.inputValues[0]) + } + verifyNoMoreInteractions(mockBuilderDelegate) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputItemTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputItemTest.kt new file mode 100644 index 000000000..2ba6fa031 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputItemTest.kt @@ -0,0 +1,204 @@ +package com.openai.models.responses + +import com.openai.core.DelegationReadTestCase +import com.openai.core.LIST +import com.openai.core.OPTIONAL +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorReadFunctionsAreTested +import com.openai.core.checkOneDelegationRead +import java.util.Optional +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredResponseOutputItem] class (delegator) and its delegation of most + * functions to a wrapped [ResponseOutputItem] (delegate). The tests include confirmation of the + * following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredResponseOutputItemTest { + companion object { + private val FILE_SEARCH_TOOL_CALL = + ResponseFileSearchToolCall.builder() + .id(STRING) + .queries(LIST) + .status(ResponseFileSearchToolCall.Status.COMPLETED) + .build() + private val FUNCTION_TOOL_CALL = + ResponseFunctionToolCall.builder().arguments(STRING).callId(STRING).name(STRING).build() + private val FUNCTION_WEB_SEARCH = + ResponseFunctionWebSearch.builder() + .id(STRING) + .status(ResponseFunctionWebSearch.Status.COMPLETED) + .build() + private val COMPUTER_TOOL_CALL = + ResponseComputerToolCall.builder() + .id(STRING) + .action(ResponseComputerToolCall.Action.ofWait()) + .callId(STRING) + .pendingSafetyChecks(listOf()) + .status(ResponseComputerToolCall.Status.COMPLETED) + .type(ResponseComputerToolCall.Type.COMPUTER_CALL) + .build() + private val REASONING_ITEM = + ResponseReasoningItem.builder().id(STRING).summary(listOf()).build() + private val MESSAGE = + ResponseOutputMessage.builder() + .id(STRING) + .content(listOf()) + .status(ResponseOutputMessage.Status.COMPLETED) + .build() + + // The list order follows the declaration order in `ResponseOutputItem` for easier + // maintenance. + @JvmStatic + private fun delegationTestCases() = + listOf( + // `message()` is a special case and has its own test function. + DelegationReadTestCase("fileSearchCall", OPTIONAL), + DelegationReadTestCase("functionCall", OPTIONAL), + DelegationReadTestCase("webSearchCall", OPTIONAL), + DelegationReadTestCase("computerCall", OPTIONAL), + DelegationReadTestCase("reasoning", OPTIONAL), + // `isMessage()` is a special case and has its own test function. + // For the Boolean functions, call each in turn with both `true` and `false` to + // ensure that a return value is not hard-coded. + DelegationReadTestCase("isFileSearchCall", true), + DelegationReadTestCase("isFileSearchCall", false), + DelegationReadTestCase("isFunctionCall", true), + DelegationReadTestCase("isFunctionCall", false), + DelegationReadTestCase("isWebSearchCall", true), + DelegationReadTestCase("isWebSearchCall", false), + DelegationReadTestCase("isComputerCall", true), + DelegationReadTestCase("isComputerCall", false), + DelegationReadTestCase("isReasoning", true), + DelegationReadTestCase("isReasoning", false), + // `asMessage()` is a special case and has its own test function. + DelegationReadTestCase("asFileSearchCall", FILE_SEARCH_TOOL_CALL), + DelegationReadTestCase("asFunctionCall", FUNCTION_TOOL_CALL), + DelegationReadTestCase("asWebSearchCall", FUNCTION_WEB_SEARCH), + DelegationReadTestCase("asComputerCall", COMPUTER_TOOL_CALL), + DelegationReadTestCase("asReasoning", REASONING_ITEM), + DelegationReadTestCase("_json", OPTIONAL), + ) + } + + // New instances of the `mockDelegate` and `delegator` are required for each test case (each + // test case runs in its own instance of the test class). + private val mockDelegate: ResponseOutputItem = mock(ResponseOutputItem::class.java) + private val delegator = StructuredResponseOutputItem(X::class.java, mockDelegate) + + @Test + fun allDelegateFunctionsExistInDelegator() { + // `toBuilder()` is deliberately not implemented. `accept()` has a different signature. + checkAllDelegation(mockDelegate::class, delegator::class, "toBuilder", "accept") + } + + @Test + fun allDelegatorFunctionsExistInDelegate() { + // `accept()` has a different signature. + checkAllDelegation(delegator::class, mockDelegate::class, "accept") + } + + @Test + fun allDelegatorFunctionsAreTested() { + // There are exceptional test cases for some functions. Most other functions are part of the + // list of those using the parameterized test. A few delegator functions do not delegate, so + // no test function is necessary. + checkAllDelegatorReadFunctionsAreTested( + delegator::class, + delegationTestCases(), + exceptionalTestedFns = + setOf("message", "asMessage", "isMessage", "validate", "isValid", "accept"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @ParameterizedTest + @MethodSource("delegationTestCases") + fun `delegation of functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(delegator, mockDelegate, testCase) + } + + @Test + fun `delegation of message`() { + // Input and output are different types, so this test is an exceptional case. + // The delegator's `message()` delegates to the delegate's `message()` indirectly via the + // delegator's `message` field initializer. + val input = Optional.of(MESSAGE) + `when`(mockDelegate.message()).thenReturn(input) + val output = delegator.message() + + verify(mockDelegate, times(1)).message() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output.get().rawMessage).isEqualTo(MESSAGE) + } + + @Test + fun `delegation of asMessage`() { + // Delegation function names do not match, so this test is an exceptional case. + // The delegator's `asMessage()` delegates to the delegate's `message()` (without the "as") + // indirectly via the delegator's `message` field initializer. + val input = Optional.of(MESSAGE) + `when`(mockDelegate.message()).thenReturn(input) + val output = delegator.asMessage() + + verify(mockDelegate, times(1)).message() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output.rawMessage).isEqualTo(MESSAGE) + } + + @Test + fun `delegation of isMessage`() { + // Delegation function names do not match, so this test is an exceptional case. + // The delegator's `isMessage()` delegates to the delegate's `message()` (without the "is") + // indirectly via the delegator's `message` field initializer. + val input = Optional.of(MESSAGE) + `when`(mockDelegate.message()).thenReturn(input) + val output = delegator.isMessage() + + verify(mockDelegate, times(1)).message() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output).isTrue + } + + @Test + fun `delegation of validate`() { + `when`(mockDelegate.message()).thenReturn(Optional.of(MESSAGE)) + + delegator.validate() + + // Delegator's `validate()` does not call delegate's `validate()`. `message()` is called + // indirectly via the `message` field initializer. + verify(mockDelegate, times(1)).message() + verifyNoMoreInteractions(mockDelegate) + } + + @Test + fun `delegation of isValid`() { + // `isValid` calls `validate()`, so the test is similar to that for `validate()`. + `when`(mockDelegate.message()).thenReturn(Optional.of(MESSAGE)) + + delegator.isValid() + + verify(mockDelegate, times(1)).message() + verifyNoMoreInteractions(mockDelegate) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt new file mode 100644 index 000000000..2b093cf56 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseOutputMessageTest.kt @@ -0,0 +1,285 @@ +package com.openai.models.responses + +import com.openai.core.DelegationReadTestCase +import com.openai.core.JSON_FIELD +import com.openai.core.JSON_VALUE +import com.openai.core.JsonField +import com.openai.core.MAP +import com.openai.core.OPTIONAL +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorReadFunctionsAreTested +import com.openai.core.checkOneDelegationRead +import com.openai.errors.OpenAIInvalidDataException +import java.util.Optional +import org.assertj.core.api.Assertions.assertThat +import org.assertj.core.api.Assertions.assertThatThrownBy +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredResponseOutputMessage] class (delegator) and its delegation of most + * functions to a wrapped [ResponseOutputMessage] (delegate). The tests include confirmation of the + * following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredResponseOutputMessageTest { + companion object { + private val MESSAGE_STATUS = ResponseOutputMessage.Status.COMPLETED + private val OUTPUT_TEXT = + ResponseOutputText.builder().annotations(listOf()).text(STRING).build() + private val OUTPUT_REFUSAL = ResponseOutputRefusal.builder().refusal(STRING).build() + private val CONTENT = ResponseOutputMessage.Content.ofOutputText(OUTPUT_TEXT) + + // The list order follows the declaration order in `ResponseOutputMessage` for easier + // maintenance. + @JvmStatic + private fun delegationTestCases() = + listOf( + DelegationReadTestCase("id", STRING), + // `content()` is a special case and has its own test function. + DelegationReadTestCase("_role", JSON_VALUE), + DelegationReadTestCase("status", MESSAGE_STATUS), + DelegationReadTestCase("_type", JSON_VALUE), + DelegationReadTestCase("_id", JSON_FIELD), + // `_content()` is a special case and has its own test function. + DelegationReadTestCase("_status", JSON_FIELD), + DelegationReadTestCase("_additionalProperties", MAP), + ) + + // The list order follows the declaration order in `ResponseOutputMessage.Content` for + // easier maintenance. + @JvmStatic + private fun contentDelegationTestCases() = + listOf( + // `outputText()` is a special case and has its own test function. + DelegationReadTestCase("refusal", OPTIONAL), + // For the Boolean functions, pass both `true` and `false` to ensure that one value + // is not hard-coded. + DelegationReadTestCase("isOutputText", true), + DelegationReadTestCase("isOutputText", false), + DelegationReadTestCase("isRefusal", true), + DelegationReadTestCase("isRefusal", false), + // `asOutputText()` is a special case and has its own test function. + DelegationReadTestCase("asRefusal", OUTPUT_REFUSAL), + DelegationReadTestCase("_json", OPTIONAL), + ) + } + + // New instances of the `mockDelegate` and `delegator` are required for each test case (each + // test case runs in its own instance of the test class). + private val mockDelegate: ResponseOutputMessage = mock(ResponseOutputMessage::class.java) + private val delegator = StructuredResponseOutputMessage(X::class.java, mockDelegate) + + private val contentMockDelegate: ResponseOutputMessage.Content = + mock(ResponseOutputMessage.Content::class.java) + private val contentDelegator = + StructuredResponseOutputMessage.Content(X::class.java, contentMockDelegate) + + @Test + fun allDelegateFunctionsExistInDelegator() { + checkAllDelegation(mockDelegate::class, delegator::class, "toBuilder") + } + + @Test + fun allDelegatorFunctionsExistInDelegate() { + checkAllDelegation(delegator::class, mockDelegate::class) + } + + @Test + fun allContentDelegateFunctionsExistInDelegator() { + // The `Content.accept()` function in the delegator takes a different type than that in the + // delegate, so there is no delegation from the former to the latter. `Content.toBuilder` is + // deliberately not implemented. + checkAllDelegation( + contentMockDelegate::class, + contentDelegator::class, + "toBuilder", + "accept", + ) + } + + @Test + fun allContentDelegatorFunctionsExistInDelegate() { + // The `Content.accept()` function in the delegator takes a different type than that in the + // delegate, so there is no delegation from the former to the latter. + checkAllDelegation(contentDelegator::class, contentMockDelegate::class, "accept") + } + + @Test + fun allDelegatorFunctionsAreTested() { + // There are exceptional test cases for some functions. Most other functions are part of the + // list of those using the parameterized test. A few delegator functions do not delegate, so + // no test function is necessary. + checkAllDelegatorReadFunctionsAreTested( + delegator::class, + delegationTestCases(), + exceptionalTestedFns = setOf("content", "_content", "validate", "isValid"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @Test + fun allContentDelegatorFunctionsAreTested() { + checkAllDelegatorReadFunctionsAreTested( + contentDelegator::class, + contentDelegationTestCases(), + exceptionalTestedFns = + setOf("outputText", "asOutputText", "validate", "isValid", "accept"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @ParameterizedTest + @MethodSource("delegationTestCases") + fun `delegation of functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(delegator, mockDelegate, testCase) + } + + @ParameterizedTest + @MethodSource("contentDelegationTestCases") + fun `delegation of Content functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(contentDelegator, contentMockDelegate, testCase) + } + + @Test + fun `delegation of content`() { + // Input and output are different types, so this test is an exceptional case. + // `content()` (without an underscore) delegates to `_content()` (with an underscore) + // indirectly via the `content` field initializer. + val input = JsonField.of(listOf(CONTENT)) + `when`(mockDelegate._content()).thenReturn(input) + val output = delegator.content() // Without an underscore. + + verify(mockDelegate, times(1))._content() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output[0].rawContent).isEqualTo(CONTENT) + } + + @Test + fun `delegation of _content`() { + // Input and output are different types, so this test is an exceptional case. + // `_content()` (with an underscore) delegates to `_content()` (with an underscore) + // indirectly via the `content` field initializer. + val input = JsonField.of(listOf(CONTENT)) + `when`(mockDelegate._content()).thenReturn(input) + val output = delegator._content() // With an underscore. + + verify(mockDelegate, times(1))._content() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output.getRequired("content")[0].rawContent).isEqualTo(CONTENT) + } + + @Test + fun `delegation of validate`() { + `when`(mockDelegate._content()).thenReturn(JsonField.of(listOf(CONTENT))) + + delegator.validate() + + // Delegator's `validate()` calls delegate's `validate()`. `_content` is called indirectly + // via the `content` field initializer. + verify(mockDelegate, times(1))._content() + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + } + + @Test + fun `delegation of isValid`() { + // `isValid` calls `validate()`, so the test is similar to that for `validate()`. + `when`(mockDelegate._content()).thenReturn(JsonField.of(listOf(CONTENT))) + + delegator.isValid() + + verify(mockDelegate, times(1))._content() + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + } + + @Test + fun `delegation of Content outputText`() { + // Input and output are different types, so this test is an exceptional case. The + // delegator's `outputText()` delegates to the delegate's `outputText()` indirectly via the + // `outputText` field initializer. + val input = + Optional.of( + ResponseOutputText.builder() + .annotations(listOf()) + .text("{\"s\" : \"hello\"}") + .build() + ) + `when`(contentMockDelegate.outputText()).thenReturn(input) + val output = contentDelegator.outputText() + + verify(contentMockDelegate, times(1)).outputText() + verifyNoMoreInteractions(contentMockDelegate) + + assertThat(output).isEqualTo(Optional.of(X("hello"))) + } + + @Test + fun `delegation of Content asOutputText`() { + // Input and output are different types, so this test is an exceptional case. The + // delegator's `asOutputText()` delegates to the delegate's `outputText()` indirectly via + // the + // `outputText` field initializer. + val input = + Optional.of( + ResponseOutputText.builder() + .annotations(listOf()) + .text("{\"s\" : \"hello\"}") + .build() + ) + `when`(contentMockDelegate.outputText()).thenReturn(input) + val output = contentDelegator.asOutputText() + + verify(contentMockDelegate, times(1)).outputText() + verifyNoMoreInteractions(contentMockDelegate) + + assertThat(output).isEqualTo(X("hello")) + } + + @Test + fun `delegation of Content asOutputText missing`() { + val input = Optional.ofNullable(null) + `when`(contentMockDelegate.outputText()).thenReturn(input) + + assertThatThrownBy { contentDelegator.asOutputText() } + .isInstanceOf(OpenAIInvalidDataException::class.java) + .hasMessage("`outputText` is not present") + + verify(contentMockDelegate, times(1)).outputText() + verifyNoMoreInteractions(contentMockDelegate) + } + + @Test + fun `delegation of Content validate`() { + // No values or passed and only `this` is returned. + contentDelegator.validate() + + verify(contentMockDelegate, times(1)).validate() + verifyNoMoreInteractions(contentMockDelegate) + } + + @Test + fun `delegation of Content isValid`() { + contentDelegator.isValid() + + // `isValid()` calls `validate`, which then calls the mock delegate. + verify(contentMockDelegate, times(1)).validate() + verifyNoMoreInteractions(contentMockDelegate) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt new file mode 100644 index 000000000..9a1b76cd1 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/models/responses/StructuredResponseTest.kt @@ -0,0 +1,197 @@ +package com.openai.models.responses + +import com.openai.core.BOOLEAN +import com.openai.core.DOUBLE +import com.openai.core.DelegationReadTestCase +import com.openai.core.JSON_FIELD +import com.openai.core.JSON_VALUE +import com.openai.core.JsonField +import com.openai.core.LIST +import com.openai.core.MAP +import com.openai.core.OPTIONAL +import com.openai.core.STRING +import com.openai.core.X +import com.openai.core.checkAllDelegation +import com.openai.core.checkAllDelegatorReadFunctionsAreTested +import com.openai.core.checkOneDelegationRead +import com.openai.models.ChatModel +import com.openai.models.ResponsesModel +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.MethodSource +import org.mockito.Mockito.mock +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.Mockito.`when` +import org.mockito.kotlin.times +import org.mockito.kotlin.verify + +/** + * Unit tests for the [StructuredResponse] class (delegator) and its delegation of most functions to + * a wrapped [Response] (delegate). The tests include confirmation of the following: + * - All functions in the delegator correspond to a function in the delegate and _vice versa_. + * - All functions in the delegator call their corresponding function in the delegate and only that + * function. + * - A unit test exists for all functions. + * + * There are some exceptions to the above that are handled differently. + */ +internal class StructuredResponseTest { + companion object { + private val RESPONSES_MODEL = ResponsesModel.ofChat(ChatModel.GPT_4O) + + private val TOOL_CHOICE = + Response.ToolChoice.ofFunction(ToolChoiceFunction.builder().name(STRING).build()) + // A reasoning item is probably the simplest one to create. + private val OUTPUT_ITEM = + ResponseOutputItem.ofReasoning( + ResponseReasoningItem.builder() + .id(STRING) + .summary(listOf(ResponseReasoningItem.Summary.builder().text(STRING).build())) + .build() + ) + + // The list order follows the declaration order in `Response` for easier maintenance. + @JvmStatic + private fun delegationTestCases() = + listOf( + DelegationReadTestCase("id", STRING), + DelegationReadTestCase("createdAt", DOUBLE), + DelegationReadTestCase("error", OPTIONAL), + DelegationReadTestCase("incompleteDetails", OPTIONAL), + DelegationReadTestCase("instructions", OPTIONAL), + DelegationReadTestCase("metadata", OPTIONAL), + DelegationReadTestCase("model", RESPONSES_MODEL), + DelegationReadTestCase("_object_", JSON_VALUE), + // `output()` is a special case and has its own test function. + DelegationReadTestCase("parallelToolCalls", BOOLEAN), + DelegationReadTestCase("temperature", OPTIONAL), + DelegationReadTestCase("toolChoice", TOOL_CHOICE), + DelegationReadTestCase("tools", LIST), + DelegationReadTestCase("topP", OPTIONAL), + DelegationReadTestCase("maxOutputTokens", OPTIONAL), + DelegationReadTestCase("previousResponseId", OPTIONAL), + DelegationReadTestCase("reasoning", OPTIONAL), + DelegationReadTestCase("serviceTier", OPTIONAL), + DelegationReadTestCase("status", OPTIONAL), + DelegationReadTestCase("text", OPTIONAL), + DelegationReadTestCase("truncation", OPTIONAL), + DelegationReadTestCase("usage", OPTIONAL), + DelegationReadTestCase("user", OPTIONAL), + DelegationReadTestCase("_id", JSON_FIELD), + DelegationReadTestCase("_createdAt", JSON_FIELD), + DelegationReadTestCase("_error", JSON_FIELD), + DelegationReadTestCase("_incompleteDetails", JSON_FIELD), + DelegationReadTestCase("_instructions", JSON_FIELD), + DelegationReadTestCase("_metadata", JSON_FIELD), + DelegationReadTestCase("_model", JSON_FIELD), + // `_output()` is a special case and has its own test function. + DelegationReadTestCase("_parallelToolCalls", JSON_FIELD), + DelegationReadTestCase("_temperature", JSON_FIELD), + DelegationReadTestCase("_toolChoice", JSON_FIELD), + DelegationReadTestCase("_tools", JSON_FIELD), + DelegationReadTestCase("_topP", JSON_FIELD), + DelegationReadTestCase("_maxOutputTokens", JSON_FIELD), + DelegationReadTestCase("_previousResponseId", JSON_FIELD), + DelegationReadTestCase("_reasoning", JSON_FIELD), + DelegationReadTestCase("_serviceTier", JSON_FIELD), + DelegationReadTestCase("_status", JSON_FIELD), + DelegationReadTestCase("_text", JSON_FIELD), + DelegationReadTestCase("_truncation", JSON_FIELD), + DelegationReadTestCase("_usage", JSON_FIELD), + DelegationReadTestCase("_user", JSON_FIELD), + DelegationReadTestCase("_additionalProperties", MAP), + // `validate()` and `isValid()` (which calls `validate()`) are tested separately, + // as they require special handling. + ) + } + + // New instances of the `mockDelegate` and `delegator` are required for each test case (each + // test case runs in its own instance of the test class). + private val mockDelegate: Response = mock(Response::class.java) + private val delegator = StructuredResponse(X::class.java, mockDelegate) + + @Test + fun allDelegateFunctionsExistInDelegator() { + checkAllDelegation(mockDelegate::class, delegator::class, "toBuilder") + } + + @Test + fun allDelegatorFunctionsExistInDelegate() { + checkAllDelegation(delegator::class, mockDelegate::class) + } + + @Test + fun allDelegatorFunctionsAreTested() { + // There are exceptional test cases for some functions. Most other functions are part of the + // list of those using the parameterized test. A few delegator functions do not delegate, so + // no test function is necessary. + checkAllDelegatorReadFunctionsAreTested( + delegator::class, + delegationTestCases(), + exceptionalTestedFns = setOf("output", "_output", "validate", "isValid"), + nonDelegatingFns = setOf("equals", "hashCode", "toString"), + ) + } + + @ParameterizedTest + @MethodSource("delegationTestCases") + fun `delegation of functions in general`(testCase: DelegationReadTestCase) { + checkOneDelegationRead(delegator, mockDelegate, testCase) + } + + @Test + fun `delegation of output`() { + // Input and output are different types, so this test is an exceptional case. + // `output()` (without an underscore) delegates to `_output()` (with an underscore) + // indirectly via the `output` field initializer. + val input = JsonField.of(listOf(OUTPUT_ITEM)) + `when`(mockDelegate._output()).thenReturn(input) + val output = delegator.output() // Without an underscore. + + verify(mockDelegate, times(1))._output() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output[0].rawOutputItem).isEqualTo(OUTPUT_ITEM) + } + + @Test + fun `delegation of _output`() { + // Input and output are different types, so this test is an exceptional case. + // `_output()` delegates to `_output()` indirectly via the `output` field initializer. + val input = JsonField.of(listOf(OUTPUT_ITEM)) + `when`(mockDelegate._output()).thenReturn(input) + val output = delegator._output() // With an underscore. + + verify(mockDelegate, times(1))._output() + verifyNoMoreInteractions(mockDelegate) + + assertThat(output.getRequired("_output")[0].rawOutputItem).isEqualTo(OUTPUT_ITEM) + } + + @Test + fun `delegation of validate`() { + `when`(mockDelegate._output()).thenReturn(JsonField.of(listOf(OUTPUT_ITEM))) + + delegator.validate() + + // Delegator's `validate()` calls the delegate's `validate()`. Delegate's `_output()` is + // called indirectly via the `output` field initializer. + verify(mockDelegate, times(1))._output() // Indirect + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + } + + @Test + fun `delegation of isValid`() { + // `isValid()` calls `validate()` which delegates to `validate()`, so the test is + // more-or-less the same as for `validate()`. + `when`(mockDelegate._output()).thenReturn(JsonField.of(listOf(OUTPUT_ITEM))) + + delegator.isValid() + + verify(mockDelegate, times(1))._output() // Indirect + verify(mockDelegate, times(1)).validate() + verifyNoMoreInteractions(mockDelegate) + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/services/ErrorHandlingTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/ErrorHandlingTest.kt index f7e594be5..f19d5a985 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/ErrorHandlingTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/ErrorHandlingTest.kt @@ -23,6 +23,13 @@ import com.openai.errors.UnauthorizedException import com.openai.errors.UnexpectedStatusCodeException import com.openai.errors.UnprocessableEntityException import com.openai.models.finetuning.jobs.JobCreateParams +import com.openai.models.finetuning.methods.DpoHyperparameters +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementHyperparameters +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedHyperparameters +import com.openai.models.finetuning.methods.SupervisedMethod +import com.openai.models.graders.gradermodels.StringCheckGrader import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.entry import org.junit.jupiter.api.BeforeEach @@ -111,10 +118,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -123,11 +131,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -135,7 +168,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -202,10 +234,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -214,11 +247,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -226,7 +284,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -293,10 +350,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -305,11 +363,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -317,7 +400,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -384,10 +466,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -396,11 +479,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -408,7 +516,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -475,10 +582,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -487,11 +595,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -499,7 +632,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -566,10 +698,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -578,11 +711,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -590,7 +748,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -657,10 +814,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -669,11 +827,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -681,7 +864,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -748,10 +930,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -760,11 +943,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -772,7 +980,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -837,10 +1044,11 @@ internal class ErrorHandlingTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -849,11 +1057,36 @@ internal class ErrorHandlingTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort + .DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters - .builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -861,7 +1094,6 @@ internal class ErrorHandlingTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/BatchServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/BatchServiceAsyncTest.kt index 25228c552..bddf750dd 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/BatchServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/BatchServiceAsyncTest.kt @@ -5,9 +5,7 @@ package com.openai.services.async import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync import com.openai.core.JsonValue -import com.openai.models.batches.BatchCancelParams import com.openai.models.batches.BatchCreateParams -import com.openai.models.batches.BatchRetrieveParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -50,8 +48,7 @@ internal class BatchServiceAsyncTest { .build() val batchServiceAsync = client.batches() - val batchFuture = - batchServiceAsync.retrieve(BatchRetrieveParams.builder().batchId("batch_id").build()) + val batchFuture = batchServiceAsync.retrieve("batch_id") val batch = batchFuture.get() batch.validate() @@ -81,8 +78,7 @@ internal class BatchServiceAsyncTest { .build() val batchServiceAsync = client.batches() - val batchFuture = - batchServiceAsync.cancel(BatchCancelParams.builder().batchId("batch_id").build()) + val batchFuture = batchServiceAsync.cancel("batch_id") val batch = batchFuture.get() batch.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/EvalServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/EvalServiceAsyncTest.kt index b4a7c4fb2..1f940b245 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/EvalServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/EvalServiceAsyncTest.kt @@ -6,8 +6,6 @@ import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync import com.openai.core.JsonValue import com.openai.models.evals.EvalCreateParams -import com.openai.models.evals.EvalDeleteParams -import com.openai.models.evals.EvalRetrieveParams import com.openai.models.evals.EvalUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -75,8 +73,7 @@ internal class EvalServiceAsyncTest { .build() val evalServiceAsync = client.evals() - val evalFuture = - evalServiceAsync.retrieve(EvalRetrieveParams.builder().evalId("eval_id").build()) + val evalFuture = evalServiceAsync.retrieve("eval_id") val eval = evalFuture.get() eval.validate() @@ -132,8 +129,7 @@ internal class EvalServiceAsyncTest { .build() val evalServiceAsync = client.evals() - val evalFuture = - evalServiceAsync.delete(EvalDeleteParams.builder().evalId("eval_id").build()) + val evalFuture = evalServiceAsync.delete("eval_id") val eval = evalFuture.get() eval.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/FileServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/FileServiceAsyncTest.kt index 6c8af86c5..0156759e4 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/FileServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/FileServiceAsyncTest.kt @@ -10,11 +10,8 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync -import com.openai.models.files.FileContentParams import com.openai.models.files.FileCreateParams -import com.openai.models.files.FileDeleteParams import com.openai.models.files.FilePurpose -import com.openai.models.files.FileRetrieveParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -55,8 +52,7 @@ internal class FileServiceAsyncTest { .build() val fileServiceAsync = client.files() - val fileObjectFuture = - fileServiceAsync.retrieve(FileRetrieveParams.builder().fileId("file_id").build()) + val fileObjectFuture = fileServiceAsync.retrieve("file_id") val fileObject = fileObjectFuture.get() fileObject.validate() @@ -86,8 +82,7 @@ internal class FileServiceAsyncTest { .build() val fileServiceAsync = client.files() - val fileDeletedFuture = - fileServiceAsync.delete(FileDeleteParams.builder().fileId("file_id").build()) + val fileDeletedFuture = fileServiceAsync.delete("file_id") val fileDeleted = fileDeletedFuture.get() fileDeleted.validate() @@ -103,8 +98,7 @@ internal class FileServiceAsyncTest { val fileServiceAsync = client.files() stubFor(get(anyUrl()).willReturn(ok().withBody("abc"))) - val responseFuture = - fileServiceAsync.content(FileContentParams.builder().fileId("file_id").build()) + val responseFuture = fileServiceAsync.content("file_id") val response = responseFuture.get() assertThat(response.body()).hasContent("abc") diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/ModelServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/ModelServiceAsyncTest.kt index 25b7ab235..95ab7c7f0 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/ModelServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/ModelServiceAsyncTest.kt @@ -4,8 +4,6 @@ package com.openai.services.async import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync -import com.openai.models.models.ModelDeleteParams -import com.openai.models.models.ModelRetrieveParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -21,8 +19,7 @@ internal class ModelServiceAsyncTest { .build() val modelServiceAsync = client.models() - val modelFuture = - modelServiceAsync.retrieve(ModelRetrieveParams.builder().model("gpt-4o-mini").build()) + val modelFuture = modelServiceAsync.retrieve("gpt-4o-mini") val model = modelFuture.get() model.validate() @@ -52,10 +49,7 @@ internal class ModelServiceAsyncTest { .build() val modelServiceAsync = client.models() - val modelDeletedFuture = - modelServiceAsync.delete( - ModelDeleteParams.builder().model("ft:gpt-4o-mini:acemeco:suffix:abc123").build() - ) + val modelDeletedFuture = modelServiceAsync.delete("ft:gpt-4o-mini:acemeco:suffix:abc123") val modelDeleted = modelDeletedFuture.get() modelDeleted.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/ResponseServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/ResponseServiceAsyncTest.kt index a7f6183b4..8e6658e3c 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/ResponseServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/ResponseServiceAsyncTest.kt @@ -12,7 +12,6 @@ import com.openai.models.ReasoningEffort import com.openai.models.ResponseFormatText import com.openai.models.responses.FileSearchTool import com.openai.models.responses.ResponseCreateParams -import com.openai.models.responses.ResponseDeleteParams import com.openai.models.responses.ResponseIncludable import com.openai.models.responses.ResponseRetrieveParams import com.openai.models.responses.ResponseTextConfig @@ -192,12 +191,7 @@ internal class ResponseServiceAsyncTest { .build() val responseServiceAsync = client.responses() - val future = - responseServiceAsync.delete( - ResponseDeleteParams.builder() - .responseId("resp_677efb5139a88190b512bc3fef8e535d") - .build() - ) + val future = responseServiceAsync.delete("resp_677efb5139a88190b512bc3fef8e535d") val response = future.get() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/UploadServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/UploadServiceAsyncTest.kt index 0b652b221..48edbd353 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/UploadServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/UploadServiceAsyncTest.kt @@ -5,7 +5,6 @@ package com.openai.services.async import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync import com.openai.models.files.FilePurpose -import com.openai.models.uploads.UploadCancelParams import com.openai.models.uploads.UploadCompleteParams import com.openai.models.uploads.UploadCreateParams import org.junit.jupiter.api.Test @@ -46,10 +45,7 @@ internal class UploadServiceAsyncTest { .build() val uploadServiceAsync = client.uploads() - val uploadFuture = - uploadServiceAsync.cancel( - UploadCancelParams.builder().uploadId("upload_abc123").build() - ) + val uploadFuture = uploadServiceAsync.cancel("upload_abc123") val upload = uploadFuture.get() upload.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/VectorStoreServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/VectorStoreServiceAsyncTest.kt index 90a9bf882..63306b105 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/VectorStoreServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/VectorStoreServiceAsyncTest.kt @@ -7,8 +7,6 @@ import com.openai.client.okhttp.OpenAIOkHttpClientAsync import com.openai.core.JsonValue import com.openai.models.vectorstores.AutoFileChunkingStrategyParam import com.openai.models.vectorstores.VectorStoreCreateParams -import com.openai.models.vectorstores.VectorStoreDeleteParams -import com.openai.models.vectorstores.VectorStoreRetrieveParams import com.openai.models.vectorstores.VectorStoreSearchParams import com.openai.models.vectorstores.VectorStoreUpdateParams import org.junit.jupiter.api.Test @@ -54,10 +52,7 @@ internal class VectorStoreServiceAsyncTest { .build() val vectorStoreServiceAsync = client.vectorStores() - val vectorStoreFuture = - vectorStoreServiceAsync.retrieve( - VectorStoreRetrieveParams.builder().vectorStoreId("vector_store_id").build() - ) + val vectorStoreFuture = vectorStoreServiceAsync.retrieve("vector_store_id") val vectorStore = vectorStoreFuture.get() vectorStore.validate() @@ -114,10 +109,7 @@ internal class VectorStoreServiceAsyncTest { .build() val vectorStoreServiceAsync = client.vectorStores() - val vectorStoreDeletedFuture = - vectorStoreServiceAsync.delete( - VectorStoreDeleteParams.builder().vectorStoreId("vector_store_id").build() - ) + val vectorStoreDeletedFuture = vectorStoreServiceAsync.delete("vector_store_id") val vectorStoreDeleted = vectorStoreDeletedFuture.get() vectorStoreDeleted.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/AssistantServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/AssistantServiceAsyncTest.kt index b731d4938..bf5eebb46 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/AssistantServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/AssistantServiceAsyncTest.kt @@ -8,8 +8,6 @@ import com.openai.core.JsonValue import com.openai.models.ChatModel import com.openai.models.ReasoningEffort import com.openai.models.beta.assistants.AssistantCreateParams -import com.openai.models.beta.assistants.AssistantDeleteParams -import com.openai.models.beta.assistants.AssistantRetrieveParams import com.openai.models.beta.assistants.AssistantUpdateParams import com.openai.models.beta.assistants.CodeInterpreterTool import org.junit.jupiter.api.Test @@ -92,10 +90,7 @@ internal class AssistantServiceAsyncTest { .build() val assistantServiceAsync = client.beta().assistants() - val assistantFuture = - assistantServiceAsync.retrieve( - AssistantRetrieveParams.builder().assistantId("assistant_id").build() - ) + val assistantFuture = assistantServiceAsync.retrieve("assistant_id") val assistant = assistantFuture.get() assistant.validate() @@ -173,10 +168,7 @@ internal class AssistantServiceAsyncTest { .build() val assistantServiceAsync = client.beta().assistants() - val assistantDeletedFuture = - assistantServiceAsync.delete( - AssistantDeleteParams.builder().assistantId("assistant_id").build() - ) + val assistantDeletedFuture = assistantServiceAsync.delete("assistant_id") val assistantDeleted = assistantDeletedFuture.get() assistantDeleted.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/ThreadServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/ThreadServiceAsyncTest.kt index cb993034a..91ba504c5 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/ThreadServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/ThreadServiceAsyncTest.kt @@ -10,8 +10,6 @@ import com.openai.models.beta.assistants.CodeInterpreterTool import com.openai.models.beta.threads.AssistantToolChoiceOption import com.openai.models.beta.threads.ThreadCreateAndRunParams import com.openai.models.beta.threads.ThreadCreateParams -import com.openai.models.beta.threads.ThreadDeleteParams -import com.openai.models.beta.threads.ThreadRetrieveParams import com.openai.models.beta.threads.ThreadUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -101,10 +99,7 @@ internal class ThreadServiceAsyncTest { .build() val threadServiceAsync = client.beta().threads() - val threadFuture = - threadServiceAsync.retrieve( - ThreadRetrieveParams.builder().threadId("thread_id").build() - ) + val threadFuture = threadServiceAsync.retrieve("thread_id") val thread = threadFuture.get() thread.validate() @@ -158,8 +153,7 @@ internal class ThreadServiceAsyncTest { .build() val threadServiceAsync = client.beta().threads() - val threadDeletedFuture = - threadServiceAsync.delete(ThreadDeleteParams.builder().threadId("thread_id").build()) + val threadDeletedFuture = threadServiceAsync.delete("thread_id") val threadDeleted = threadDeletedFuture.get() threadDeleted.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncTest.kt index 14c21f5c2..088486d7e 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/MessageServiceAsyncTest.kt @@ -8,7 +8,6 @@ import com.openai.core.JsonValue import com.openai.models.beta.assistants.CodeInterpreterTool import com.openai.models.beta.threads.messages.MessageCreateParams import com.openai.models.beta.threads.messages.MessageDeleteParams -import com.openai.models.beta.threads.messages.MessageListParams import com.openai.models.beta.threads.messages.MessageRetrieveParams import com.openai.models.beta.threads.messages.MessageUpdateParams import org.junit.jupiter.api.Test @@ -106,8 +105,7 @@ internal class MessageServiceAsyncTest { .build() val messageServiceAsync = client.beta().threads().messages() - val pageFuture = - messageServiceAsync.list(MessageListParams.builder().threadId("thread_id").build()) + val pageFuture = messageServiceAsync.list("thread_id") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncTest.kt index 70bdc4c70..51885c40e 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/beta/threads/RunServiceAsyncTest.kt @@ -11,7 +11,6 @@ import com.openai.models.beta.assistants.CodeInterpreterTool import com.openai.models.beta.threads.AssistantToolChoiceOption import com.openai.models.beta.threads.runs.RunCancelParams import com.openai.models.beta.threads.runs.RunCreateParams -import com.openai.models.beta.threads.runs.RunListParams import com.openai.models.beta.threads.runs.RunRetrieveParams import com.openai.models.beta.threads.runs.RunSubmitToolOutputsParams import com.openai.models.beta.threads.runs.RunUpdateParams @@ -200,7 +199,7 @@ internal class RunServiceAsyncTest { .build() val runServiceAsync = client.beta().threads().runs() - val pageFuture = runServiceAsync.list(RunListParams.builder().threadId("thread_id").build()) + val pageFuture = runServiceAsync.list("thread_id") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncTest.kt index 029284428..693c02d26 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/chat/ChatCompletionServiceAsyncTest.kt @@ -12,10 +12,8 @@ import com.openai.models.ReasoningEffort import com.openai.models.ResponseFormatText import com.openai.models.chat.completions.ChatCompletionAudioParam import com.openai.models.chat.completions.ChatCompletionCreateParams -import com.openai.models.chat.completions.ChatCompletionDeleteParams import com.openai.models.chat.completions.ChatCompletionDeveloperMessageParam import com.openai.models.chat.completions.ChatCompletionPredictionContent -import com.openai.models.chat.completions.ChatCompletionRetrieveParams import com.openai.models.chat.completions.ChatCompletionStreamOptions import com.openai.models.chat.completions.ChatCompletionTool import com.openai.models.chat.completions.ChatCompletionToolChoiceOption @@ -262,10 +260,7 @@ internal class ChatCompletionServiceAsyncTest { .build() val chatCompletionServiceAsync = client.chat().completions() - val chatCompletionFuture = - chatCompletionServiceAsync.retrieve( - ChatCompletionRetrieveParams.builder().completionId("completion_id").build() - ) + val chatCompletionFuture = chatCompletionServiceAsync.retrieve("completion_id") val chatCompletion = chatCompletionFuture.get() chatCompletion.validate() @@ -320,10 +315,7 @@ internal class ChatCompletionServiceAsyncTest { .build() val chatCompletionServiceAsync = client.chat().completions() - val chatCompletionDeletedFuture = - chatCompletionServiceAsync.delete( - ChatCompletionDeleteParams.builder().completionId("completion_id").build() - ) + val chatCompletionDeletedFuture = chatCompletionServiceAsync.delete("completion_id") val chatCompletionDeleted = chatCompletionDeletedFuture.get() chatCompletionDeleted.validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncTest.kt index 5fbbb2fa3..2c834f1f2 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/chat/completions/MessageServiceAsyncTest.kt @@ -4,7 +4,6 @@ package com.openai.services.async.chat.completions import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync -import com.openai.models.chat.completions.messages.MessageListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,10 +19,7 @@ internal class MessageServiceAsyncTest { .build() val messageServiceAsync = client.chat().completions().messages() - val pageFuture = - messageServiceAsync.list( - MessageListParams.builder().completionId("completion_id").build() - ) + val pageFuture = messageServiceAsync.list("completion_id") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/evals/RunServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/evals/RunServiceAsyncTest.kt index 22e9d8e98..2f6212977 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/evals/RunServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/evals/RunServiceAsyncTest.kt @@ -9,7 +9,6 @@ import com.openai.models.evals.runs.CreateEvalJsonlRunDataSource import com.openai.models.evals.runs.RunCancelParams import com.openai.models.evals.runs.RunCreateParams import com.openai.models.evals.runs.RunDeleteParams -import com.openai.models.evals.runs.RunListParams import com.openai.models.evals.runs.RunRetrieveParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -95,7 +94,7 @@ internal class RunServiceAsyncTest { .build() val runServiceAsync = client.evals().runs() - val pageFuture = runServiceAsync.list(RunListParams.builder().evalId("eval_id").build()) + val pageFuture = runServiceAsync.list("eval_id") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/JobServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/JobServiceAsyncTest.kt index 69cee8abe..6a9b1aef6 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/JobServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/JobServiceAsyncTest.kt @@ -5,10 +5,14 @@ package com.openai.services.async.finetuning import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync import com.openai.core.JsonValue -import com.openai.models.finetuning.jobs.JobCancelParams import com.openai.models.finetuning.jobs.JobCreateParams -import com.openai.models.finetuning.jobs.JobListEventsParams -import com.openai.models.finetuning.jobs.JobRetrieveParams +import com.openai.models.finetuning.methods.DpoHyperparameters +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementHyperparameters +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedHyperparameters +import com.openai.models.finetuning.methods.SupervisedMethod +import com.openai.models.graders.gradermodels.StringCheckGrader import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -55,10 +59,11 @@ internal class JobServiceAsyncTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -67,10 +72,35 @@ internal class JobServiceAsyncTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -78,7 +108,6 @@ internal class JobServiceAsyncTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -100,10 +129,7 @@ internal class JobServiceAsyncTest { .build() val jobServiceAsync = client.fineTuning().jobs() - val fineTuningJobFuture = - jobServiceAsync.retrieve( - JobRetrieveParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() - ) + val fineTuningJobFuture = jobServiceAsync.retrieve("ft-AF1WoRqd3aJAHsqc9NY7iL8F") val fineTuningJob = fineTuningJobFuture.get() fineTuningJob.validate() @@ -133,10 +159,7 @@ internal class JobServiceAsyncTest { .build() val jobServiceAsync = client.fineTuning().jobs() - val fineTuningJobFuture = - jobServiceAsync.cancel( - JobCancelParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() - ) + val fineTuningJobFuture = jobServiceAsync.cancel("ft-AF1WoRqd3aJAHsqc9NY7iL8F") val fineTuningJob = fineTuningJobFuture.get() fineTuningJob.validate() @@ -151,12 +174,39 @@ internal class JobServiceAsyncTest { .build() val jobServiceAsync = client.fineTuning().jobs() - val pageFuture = - jobServiceAsync.listEvents( - JobListEventsParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() - ) + val pageFuture = jobServiceAsync.listEvents("ft-AF1WoRqd3aJAHsqc9NY7iL8F") val page = pageFuture.get() page.response().validate() } + + @Test + fun pause() { + val client = + OpenAIOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val jobServiceAsync = client.fineTuning().jobs() + + val fineTuningJobFuture = jobServiceAsync.pause("ft-AF1WoRqd3aJAHsqc9NY7iL8F") + + val fineTuningJob = fineTuningJobFuture.get() + fineTuningJob.validate() + } + + @Test + fun resume() { + val client = + OpenAIOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val jobServiceAsync = client.fineTuning().jobs() + + val fineTuningJobFuture = jobServiceAsync.resume("ft-AF1WoRqd3aJAHsqc9NY7iL8F") + + val fineTuningJob = fineTuningJobFuture.get() + fineTuningJob.validate() + } } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsyncTest.kt new file mode 100644 index 000000000..e6f3f90ed --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/alpha/GraderServiceAsyncTest.kt @@ -0,0 +1,71 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.async.finetuning.alpha + +import com.openai.TestServerExtension +import com.openai.client.okhttp.OpenAIOkHttpClientAsync +import com.openai.models.finetuning.alpha.graders.GraderRunParams +import com.openai.models.finetuning.alpha.graders.GraderValidateParams +import com.openai.models.graders.gradermodels.StringCheckGrader +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class GraderServiceAsyncTest { + + @Test + fun run() { + val client = + OpenAIOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val graderServiceAsync = client.fineTuning().alpha().graders() + + val responseFuture = + graderServiceAsync.run( + GraderRunParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .modelSample("model_sample") + .referenceAnswer("string") + .build() + ) + + val response = responseFuture.get() + response.validate() + } + + @Test + fun validate() { + val client = + OpenAIOkHttpClientAsync.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val graderServiceAsync = client.fineTuning().alpha().graders() + + val responseFuture = + graderServiceAsync.validate( + GraderValidateParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .build() + ) + + val response = responseFuture.get() + response.validate() + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncTest.kt index ff0521c89..75bfa2d21 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/finetuning/jobs/CheckpointServiceAsyncTest.kt @@ -4,7 +4,6 @@ package com.openai.services.async.finetuning.jobs import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync -import com.openai.models.finetuning.jobs.checkpoints.CheckpointListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,12 +19,7 @@ internal class CheckpointServiceAsyncTest { .build() val checkpointServiceAsync = client.fineTuning().jobs().checkpoints() - val pageFuture = - checkpointServiceAsync.list( - CheckpointListParams.builder() - .fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F") - .build() - ) + val pageFuture = checkpointServiceAsync.list("ft-AF1WoRqd3aJAHsqc9NY7iL8F") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/responses/InputItemServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/responses/InputItemServiceAsyncTest.kt index 241f678df..2c2953768 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/responses/InputItemServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/responses/InputItemServiceAsyncTest.kt @@ -4,7 +4,6 @@ package com.openai.services.async.responses import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClientAsync -import com.openai.models.responses.inputitems.InputItemListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,10 +19,7 @@ internal class InputItemServiceAsyncTest { .build() val inputItemServiceAsync = client.responses().inputItems() - val pageFuture = - inputItemServiceAsync.list( - InputItemListParams.builder().responseId("response_id").build() - ) + val pageFuture = inputItemServiceAsync.list("response_id") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncTest.kt index fdcfc5511..b9564abe1 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/async/vectorstores/FileServiceAsyncTest.kt @@ -9,7 +9,6 @@ import com.openai.models.vectorstores.AutoFileChunkingStrategyParam import com.openai.models.vectorstores.files.FileContentParams import com.openai.models.vectorstores.files.FileCreateParams import com.openai.models.vectorstores.files.FileDeleteParams -import com.openai.models.vectorstores.files.FileListParams import com.openai.models.vectorstores.files.FileRetrieveParams import com.openai.models.vectorstores.files.FileUpdateParams import org.junit.jupiter.api.Test @@ -101,8 +100,7 @@ internal class FileServiceAsyncTest { .build() val fileServiceAsync = client.vectorStores().files() - val pageFuture = - fileServiceAsync.list(FileListParams.builder().vectorStoreId("vector_store_id").build()) + val pageFuture = fileServiceAsync.list("vector_store_id") val page = pageFuture.get() page.response().validate() diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/BatchServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/BatchServiceTest.kt index 04ad53cdc..1a7983298 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/BatchServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/BatchServiceTest.kt @@ -5,9 +5,7 @@ package com.openai.services.blocking import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient import com.openai.core.JsonValue -import com.openai.models.batches.BatchCancelParams import com.openai.models.batches.BatchCreateParams -import com.openai.models.batches.BatchRetrieveParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -49,7 +47,7 @@ internal class BatchServiceTest { .build() val batchService = client.batches() - val batch = batchService.retrieve(BatchRetrieveParams.builder().batchId("batch_id").build()) + val batch = batchService.retrieve("batch_id") batch.validate() } @@ -77,7 +75,7 @@ internal class BatchServiceTest { .build() val batchService = client.batches() - val batch = batchService.cancel(BatchCancelParams.builder().batchId("batch_id").build()) + val batch = batchService.cancel("batch_id") batch.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/EvalServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/EvalServiceTest.kt index 940e08228..61e2c4874 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/EvalServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/EvalServiceTest.kt @@ -6,8 +6,6 @@ import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient import com.openai.core.JsonValue import com.openai.models.evals.EvalCreateParams -import com.openai.models.evals.EvalDeleteParams -import com.openai.models.evals.EvalRetrieveParams import com.openai.models.evals.EvalUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -74,7 +72,7 @@ internal class EvalServiceTest { .build() val evalService = client.evals() - val eval = evalService.retrieve(EvalRetrieveParams.builder().evalId("eval_id").build()) + val eval = evalService.retrieve("eval_id") eval.validate() } @@ -127,7 +125,7 @@ internal class EvalServiceTest { .build() val evalService = client.evals() - val eval = evalService.delete(EvalDeleteParams.builder().evalId("eval_id").build()) + val eval = evalService.delete("eval_id") eval.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/FileServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/FileServiceTest.kt index 673fbbb26..ff77adfc8 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/FileServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/FileServiceTest.kt @@ -10,11 +10,8 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo import com.github.tomakehurst.wiremock.junit5.WireMockTest import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient -import com.openai.models.files.FileContentParams import com.openai.models.files.FileCreateParams -import com.openai.models.files.FileDeleteParams import com.openai.models.files.FilePurpose -import com.openai.models.files.FileRetrieveParams import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -54,8 +51,7 @@ internal class FileServiceTest { .build() val fileService = client.files() - val fileObject = - fileService.retrieve(FileRetrieveParams.builder().fileId("file_id").build()) + val fileObject = fileService.retrieve("file_id") fileObject.validate() } @@ -83,7 +79,7 @@ internal class FileServiceTest { .build() val fileService = client.files() - val fileDeleted = fileService.delete(FileDeleteParams.builder().fileId("file_id").build()) + val fileDeleted = fileService.delete("file_id") fileDeleted.validate() } @@ -98,7 +94,7 @@ internal class FileServiceTest { val fileService = client.files() stubFor(get(anyUrl()).willReturn(ok().withBody("abc"))) - val response = fileService.content(FileContentParams.builder().fileId("file_id").build()) + val response = fileService.content("file_id") assertThat(response.body()).hasContent("abc") } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/ModelServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/ModelServiceTest.kt index 4d899a1b5..f00b554d7 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/ModelServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/ModelServiceTest.kt @@ -4,8 +4,6 @@ package com.openai.services.blocking import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient -import com.openai.models.models.ModelDeleteParams -import com.openai.models.models.ModelRetrieveParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -21,8 +19,7 @@ internal class ModelServiceTest { .build() val modelService = client.models() - val model = - modelService.retrieve(ModelRetrieveParams.builder().model("gpt-4o-mini").build()) + val model = modelService.retrieve("gpt-4o-mini") model.validate() } @@ -50,10 +47,7 @@ internal class ModelServiceTest { .build() val modelService = client.models() - val modelDeleted = - modelService.delete( - ModelDeleteParams.builder().model("ft:gpt-4o-mini:acemeco:suffix:abc123").build() - ) + val modelDeleted = modelService.delete("ft:gpt-4o-mini:acemeco:suffix:abc123") modelDeleted.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/ResponseServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/ResponseServiceTest.kt index e783dcb75..e8ae64524 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/ResponseServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/ResponseServiceTest.kt @@ -12,7 +12,6 @@ import com.openai.models.ReasoningEffort import com.openai.models.ResponseFormatText import com.openai.models.responses.FileSearchTool import com.openai.models.responses.ResponseCreateParams -import com.openai.models.responses.ResponseDeleteParams import com.openai.models.responses.ResponseIncludable import com.openai.models.responses.ResponseRetrieveParams import com.openai.models.responses.ResponseTextConfig @@ -190,10 +189,6 @@ internal class ResponseServiceTest { .build() val responseService = client.responses() - responseService.delete( - ResponseDeleteParams.builder() - .responseId("resp_677efb5139a88190b512bc3fef8e535d") - .build() - ) + responseService.delete("resp_677efb5139a88190b512bc3fef8e535d") } } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/UploadServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/UploadServiceTest.kt index 1affd622e..26afefc1b 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/UploadServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/UploadServiceTest.kt @@ -5,7 +5,6 @@ package com.openai.services.blocking import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient import com.openai.models.files.FilePurpose -import com.openai.models.uploads.UploadCancelParams import com.openai.models.uploads.UploadCompleteParams import com.openai.models.uploads.UploadCreateParams import org.junit.jupiter.api.Test @@ -45,8 +44,7 @@ internal class UploadServiceTest { .build() val uploadService = client.uploads() - val upload = - uploadService.cancel(UploadCancelParams.builder().uploadId("upload_abc123").build()) + val upload = uploadService.cancel("upload_abc123") upload.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/VectorStoreServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/VectorStoreServiceTest.kt index 8c12104ee..ba6b6886c 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/VectorStoreServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/VectorStoreServiceTest.kt @@ -7,8 +7,6 @@ import com.openai.client.okhttp.OpenAIOkHttpClient import com.openai.core.JsonValue import com.openai.models.vectorstores.AutoFileChunkingStrategyParam import com.openai.models.vectorstores.VectorStoreCreateParams -import com.openai.models.vectorstores.VectorStoreDeleteParams -import com.openai.models.vectorstores.VectorStoreRetrieveParams import com.openai.models.vectorstores.VectorStoreSearchParams import com.openai.models.vectorstores.VectorStoreUpdateParams import org.junit.jupiter.api.Test @@ -53,10 +51,7 @@ internal class VectorStoreServiceTest { .build() val vectorStoreService = client.vectorStores() - val vectorStore = - vectorStoreService.retrieve( - VectorStoreRetrieveParams.builder().vectorStoreId("vector_store_id").build() - ) + val vectorStore = vectorStoreService.retrieve("vector_store_id") vectorStore.validate() } @@ -110,10 +105,7 @@ internal class VectorStoreServiceTest { .build() val vectorStoreService = client.vectorStores() - val vectorStoreDeleted = - vectorStoreService.delete( - VectorStoreDeleteParams.builder().vectorStoreId("vector_store_id").build() - ) + val vectorStoreDeleted = vectorStoreService.delete("vector_store_id") vectorStoreDeleted.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/AssistantServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/AssistantServiceTest.kt index d6381fc68..99bf5bf28 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/AssistantServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/AssistantServiceTest.kt @@ -8,8 +8,6 @@ import com.openai.core.JsonValue import com.openai.models.ChatModel import com.openai.models.ReasoningEffort import com.openai.models.beta.assistants.AssistantCreateParams -import com.openai.models.beta.assistants.AssistantDeleteParams -import com.openai.models.beta.assistants.AssistantRetrieveParams import com.openai.models.beta.assistants.AssistantUpdateParams import com.openai.models.beta.assistants.CodeInterpreterTool import org.junit.jupiter.api.Test @@ -91,10 +89,7 @@ internal class AssistantServiceTest { .build() val assistantService = client.beta().assistants() - val assistant = - assistantService.retrieve( - AssistantRetrieveParams.builder().assistantId("assistant_id").build() - ) + val assistant = assistantService.retrieve("assistant_id") assistant.validate() } @@ -169,10 +164,7 @@ internal class AssistantServiceTest { .build() val assistantService = client.beta().assistants() - val assistantDeleted = - assistantService.delete( - AssistantDeleteParams.builder().assistantId("assistant_id").build() - ) + val assistantDeleted = assistantService.delete("assistant_id") assistantDeleted.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/ThreadServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/ThreadServiceTest.kt index aefa73189..9cba341ac 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/ThreadServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/ThreadServiceTest.kt @@ -10,8 +10,6 @@ import com.openai.models.beta.assistants.CodeInterpreterTool import com.openai.models.beta.threads.AssistantToolChoiceOption import com.openai.models.beta.threads.ThreadCreateAndRunParams import com.openai.models.beta.threads.ThreadCreateParams -import com.openai.models.beta.threads.ThreadDeleteParams -import com.openai.models.beta.threads.ThreadRetrieveParams import com.openai.models.beta.threads.ThreadUpdateParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -100,8 +98,7 @@ internal class ThreadServiceTest { .build() val threadService = client.beta().threads() - val thread = - threadService.retrieve(ThreadRetrieveParams.builder().threadId("thread_id").build()) + val thread = threadService.retrieve("thread_id") thread.validate() } @@ -153,8 +150,7 @@ internal class ThreadServiceTest { .build() val threadService = client.beta().threads() - val threadDeleted = - threadService.delete(ThreadDeleteParams.builder().threadId("thread_id").build()) + val threadDeleted = threadService.delete("thread_id") threadDeleted.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/MessageServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/MessageServiceTest.kt index be07d6559..38c0580d0 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/MessageServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/MessageServiceTest.kt @@ -8,7 +8,6 @@ import com.openai.core.JsonValue import com.openai.models.beta.assistants.CodeInterpreterTool import com.openai.models.beta.threads.messages.MessageCreateParams import com.openai.models.beta.threads.messages.MessageDeleteParams -import com.openai.models.beta.threads.messages.MessageListParams import com.openai.models.beta.threads.messages.MessageRetrieveParams import com.openai.models.beta.threads.messages.MessageUpdateParams import org.junit.jupiter.api.Test @@ -103,7 +102,7 @@ internal class MessageServiceTest { .build() val messageService = client.beta().threads().messages() - val page = messageService.list(MessageListParams.builder().threadId("thread_id").build()) + val page = messageService.list("thread_id") page.response().validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/RunServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/RunServiceTest.kt index 6394703ef..6d094b7dc 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/RunServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/beta/threads/RunServiceTest.kt @@ -11,7 +11,6 @@ import com.openai.models.beta.assistants.CodeInterpreterTool import com.openai.models.beta.threads.AssistantToolChoiceOption import com.openai.models.beta.threads.runs.RunCancelParams import com.openai.models.beta.threads.runs.RunCreateParams -import com.openai.models.beta.threads.runs.RunListParams import com.openai.models.beta.threads.runs.RunRetrieveParams import com.openai.models.beta.threads.runs.RunSubmitToolOutputsParams import com.openai.models.beta.threads.runs.RunUpdateParams @@ -195,7 +194,7 @@ internal class RunServiceTest { .build() val runService = client.beta().threads().runs() - val page = runService.list(RunListParams.builder().threadId("thread_id").build()) + val page = runService.list("thread_id") page.response().validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceTest.kt index bec6b5bb2..9475a0eba 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/ChatCompletionServiceTest.kt @@ -12,10 +12,8 @@ import com.openai.models.ReasoningEffort import com.openai.models.ResponseFormatText import com.openai.models.chat.completions.ChatCompletionAudioParam import com.openai.models.chat.completions.ChatCompletionCreateParams -import com.openai.models.chat.completions.ChatCompletionDeleteParams import com.openai.models.chat.completions.ChatCompletionDeveloperMessageParam import com.openai.models.chat.completions.ChatCompletionPredictionContent -import com.openai.models.chat.completions.ChatCompletionRetrieveParams import com.openai.models.chat.completions.ChatCompletionStreamOptions import com.openai.models.chat.completions.ChatCompletionTool import com.openai.models.chat.completions.ChatCompletionToolChoiceOption @@ -261,10 +259,7 @@ internal class ChatCompletionServiceTest { .build() val chatCompletionService = client.chat().completions() - val chatCompletion = - chatCompletionService.retrieve( - ChatCompletionRetrieveParams.builder().completionId("completion_id").build() - ) + val chatCompletion = chatCompletionService.retrieve("completion_id") chatCompletion.validate() } @@ -316,10 +311,7 @@ internal class ChatCompletionServiceTest { .build() val chatCompletionService = client.chat().completions() - val chatCompletionDeleted = - chatCompletionService.delete( - ChatCompletionDeleteParams.builder().completionId("completion_id").build() - ) + val chatCompletionDeleted = chatCompletionService.delete("completion_id") chatCompletionDeleted.validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/completions/MessageServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/completions/MessageServiceTest.kt index f591070d7..3a1a7f103 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/completions/MessageServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/chat/completions/MessageServiceTest.kt @@ -4,7 +4,6 @@ package com.openai.services.blocking.chat.completions import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient -import com.openai.models.chat.completions.messages.MessageListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,8 +19,7 @@ internal class MessageServiceTest { .build() val messageService = client.chat().completions().messages() - val page = - messageService.list(MessageListParams.builder().completionId("completion_id").build()) + val page = messageService.list("completion_id") page.response().validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/evals/RunServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/evals/RunServiceTest.kt index 42a3eaaf3..ded7e5942 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/evals/RunServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/evals/RunServiceTest.kt @@ -9,7 +9,6 @@ import com.openai.models.evals.runs.CreateEvalJsonlRunDataSource import com.openai.models.evals.runs.RunCancelParams import com.openai.models.evals.runs.RunCreateParams import com.openai.models.evals.runs.RunDeleteParams -import com.openai.models.evals.runs.RunListParams import com.openai.models.evals.runs.RunRetrieveParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -93,7 +92,7 @@ internal class RunServiceTest { .build() val runService = client.evals().runs() - val page = runService.list(RunListParams.builder().evalId("eval_id").build()) + val page = runService.list("eval_id") page.response().validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/JobServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/JobServiceTest.kt index fd91a8c0f..662a78c5e 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/JobServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/JobServiceTest.kt @@ -5,10 +5,14 @@ package com.openai.services.blocking.finetuning import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient import com.openai.core.JsonValue -import com.openai.models.finetuning.jobs.JobCancelParams import com.openai.models.finetuning.jobs.JobCreateParams -import com.openai.models.finetuning.jobs.JobListEventsParams -import com.openai.models.finetuning.jobs.JobRetrieveParams +import com.openai.models.finetuning.methods.DpoHyperparameters +import com.openai.models.finetuning.methods.DpoMethod +import com.openai.models.finetuning.methods.ReinforcementHyperparameters +import com.openai.models.finetuning.methods.ReinforcementMethod +import com.openai.models.finetuning.methods.SupervisedHyperparameters +import com.openai.models.finetuning.methods.SupervisedMethod +import com.openai.models.graders.gradermodels.StringCheckGrader import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -55,10 +59,11 @@ internal class JobServiceTest { ) .method( JobCreateParams.Method.builder() + .type(JobCreateParams.Method.Type.SUPERVISED) .dpo( - JobCreateParams.Method.Dpo.builder() + DpoMethod.builder() .hyperparameters( - JobCreateParams.Method.Dpo.Hyperparameters.builder() + DpoHyperparameters.builder() .batchSizeAuto() .betaAuto() .learningRateMultiplierAuto() @@ -67,10 +72,35 @@ internal class JobServiceTest { ) .build() ) + .reinforcement( + ReinforcementMethod.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .hyperparameters( + ReinforcementHyperparameters.builder() + .batchSizeAuto() + .computeMultiplierAuto() + .evalIntervalAuto() + .evalSamplesAuto() + .learningRateMultiplierAuto() + .nEpochsAuto() + .reasoningEffort( + ReinforcementHyperparameters.ReasoningEffort.DEFAULT + ) + .build() + ) + .build() + ) .supervised( - JobCreateParams.Method.Supervised.builder() + SupervisedMethod.builder() .hyperparameters( - JobCreateParams.Method.Supervised.Hyperparameters.builder() + SupervisedHyperparameters.builder() .batchSizeAuto() .learningRateMultiplierAuto() .nEpochsAuto() @@ -78,7 +108,6 @@ internal class JobServiceTest { ) .build() ) - .type(JobCreateParams.Method.Type.SUPERVISED) .build() ) .seed(42L) @@ -99,10 +128,7 @@ internal class JobServiceTest { .build() val jobService = client.fineTuning().jobs() - val fineTuningJob = - jobService.retrieve( - JobRetrieveParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() - ) + val fineTuningJob = jobService.retrieve("ft-AF1WoRqd3aJAHsqc9NY7iL8F") fineTuningJob.validate() } @@ -130,10 +156,7 @@ internal class JobServiceTest { .build() val jobService = client.fineTuning().jobs() - val fineTuningJob = - jobService.cancel( - JobCancelParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() - ) + val fineTuningJob = jobService.cancel("ft-AF1WoRqd3aJAHsqc9NY7iL8F") fineTuningJob.validate() } @@ -147,11 +170,36 @@ internal class JobServiceTest { .build() val jobService = client.fineTuning().jobs() - val page = - jobService.listEvents( - JobListEventsParams.builder().fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F").build() - ) + val page = jobService.listEvents("ft-AF1WoRqd3aJAHsqc9NY7iL8F") page.response().validate() } + + @Test + fun pause() { + val client = + OpenAIOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val jobService = client.fineTuning().jobs() + + val fineTuningJob = jobService.pause("ft-AF1WoRqd3aJAHsqc9NY7iL8F") + + fineTuningJob.validate() + } + + @Test + fun resume() { + val client = + OpenAIOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val jobService = client.fineTuning().jobs() + + val fineTuningJob = jobService.resume("ft-AF1WoRqd3aJAHsqc9NY7iL8F") + + fineTuningJob.validate() + } } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/alpha/GraderServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/alpha/GraderServiceTest.kt new file mode 100644 index 000000000..8d8ac5e37 --- /dev/null +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/alpha/GraderServiceTest.kt @@ -0,0 +1,69 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.openai.services.blocking.finetuning.alpha + +import com.openai.TestServerExtension +import com.openai.client.okhttp.OpenAIOkHttpClient +import com.openai.models.finetuning.alpha.graders.GraderRunParams +import com.openai.models.finetuning.alpha.graders.GraderValidateParams +import com.openai.models.graders.gradermodels.StringCheckGrader +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith + +@ExtendWith(TestServerExtension::class) +internal class GraderServiceTest { + + @Test + fun run() { + val client = + OpenAIOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val graderService = client.fineTuning().alpha().graders() + + val response = + graderService.run( + GraderRunParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .modelSample("model_sample") + .referenceAnswer("string") + .build() + ) + + response.validate() + } + + @Test + fun validate() { + val client = + OpenAIOkHttpClient.builder() + .baseUrl(TestServerExtension.BASE_URL) + .apiKey("My API Key") + .build() + val graderService = client.fineTuning().alpha().graders() + + val response = + graderService.validate( + GraderValidateParams.builder() + .grader( + StringCheckGrader.builder() + .input("input") + .name("name") + .operation(StringCheckGrader.Operation.EQ) + .reference("reference") + .build() + ) + .build() + ) + + response.validate() + } +} diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceTest.kt index 3ec97abb3..0cb543e5e 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/finetuning/jobs/CheckpointServiceTest.kt @@ -4,7 +4,6 @@ package com.openai.services.blocking.finetuning.jobs import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient -import com.openai.models.finetuning.jobs.checkpoints.CheckpointListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,12 +19,7 @@ internal class CheckpointServiceTest { .build() val checkpointService = client.fineTuning().jobs().checkpoints() - val page = - checkpointService.list( - CheckpointListParams.builder() - .fineTuningJobId("ft-AF1WoRqd3aJAHsqc9NY7iL8F") - .build() - ) + val page = checkpointService.list("ft-AF1WoRqd3aJAHsqc9NY7iL8F") page.response().validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/responses/InputItemServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/responses/InputItemServiceTest.kt index 7d3f09f0d..fa48569e8 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/responses/InputItemServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/responses/InputItemServiceTest.kt @@ -4,7 +4,6 @@ package com.openai.services.blocking.responses import com.openai.TestServerExtension import com.openai.client.okhttp.OpenAIOkHttpClient -import com.openai.models.responses.inputitems.InputItemListParams import org.junit.jupiter.api.Test import org.junit.jupiter.api.extension.ExtendWith @@ -20,8 +19,7 @@ internal class InputItemServiceTest { .build() val inputItemService = client.responses().inputItems() - val page = - inputItemService.list(InputItemListParams.builder().responseId("response_id").build()) + val page = inputItemService.list("response_id") page.response().validate() } diff --git a/openai-java-core/src/test/kotlin/com/openai/services/blocking/vectorstores/FileServiceTest.kt b/openai-java-core/src/test/kotlin/com/openai/services/blocking/vectorstores/FileServiceTest.kt index ae9bdeeb6..2c0f8c7eb 100644 --- a/openai-java-core/src/test/kotlin/com/openai/services/blocking/vectorstores/FileServiceTest.kt +++ b/openai-java-core/src/test/kotlin/com/openai/services/blocking/vectorstores/FileServiceTest.kt @@ -9,7 +9,6 @@ import com.openai.models.vectorstores.AutoFileChunkingStrategyParam import com.openai.models.vectorstores.files.FileContentParams import com.openai.models.vectorstores.files.FileCreateParams import com.openai.models.vectorstores.files.FileDeleteParams -import com.openai.models.vectorstores.files.FileListParams import com.openai.models.vectorstores.files.FileRetrieveParams import com.openai.models.vectorstores.files.FileUpdateParams import org.junit.jupiter.api.Test @@ -98,8 +97,7 @@ internal class FileServiceTest { .build() val fileService = client.vectorStores().files() - val page = - fileService.list(FileListParams.builder().vectorStoreId("vector_store_id").build()) + val page = fileService.list("vector_store_id") page.response().validate() } diff --git a/openai-java-example/src/main/java/com/openai/example/AssistantAsyncExample.java b/openai-java-example/src/main/java/com/openai/example/AssistantAsyncExample.java index 93a80bb6e..78f882317 100644 --- a/openai-java-example/src/main/java/com/openai/example/AssistantAsyncExample.java +++ b/openai-java-example/src/main/java/com/openai/example/AssistantAsyncExample.java @@ -109,18 +109,14 @@ private static CompletableFuture listThreadMessages(OpenAIClientAsync clie .order(MessageListParams.Order.ASC) .build()); return pageFuture.thenComposeAsync(page -> page.autoPager() - .forEach( - currentMessage -> { - System.out.println(currentMessage.role().toString().toUpperCase()); - currentMessage.content().stream() - .flatMap(content -> content.text().stream()) - .forEach(textBlock -> - System.out.println(textBlock.text().value())); - System.out.println(); - - // Keep iterating - return true; - }, - pageFuture.defaultExecutor())); + .subscribe(currentMessage -> { + System.out.println(currentMessage.role().toString().toUpperCase()); + currentMessage.content().stream() + .flatMap(content -> content.text().stream()) + .forEach(textBlock -> + System.out.println(textBlock.text().value())); + System.out.println(); + }) + .onCompleteFuture()); } } diff --git a/openai-java-example/src/main/java/com/openai/example/ModelListAsyncExample.java b/openai-java-example/src/main/java/com/openai/example/ModelListAsyncExample.java index 29376e7bd..3233ef08c 100644 --- a/openai-java-example/src/main/java/com/openai/example/ModelListAsyncExample.java +++ b/openai-java-example/src/main/java/com/openai/example/ModelListAsyncExample.java @@ -17,13 +17,8 @@ public static void main(String[] args) { CompletableFuture pageFuture = client.models().list(); pageFuture .thenComposeAsync(page -> page.autoPager() - .forEach( - model -> { - System.out.println(model.id()); - // Keep iterating - return true; - }, - pageFuture.defaultExecutor())) + .subscribe(model -> System.out.println(model.id())) + .onCompleteFuture()) .join(); } } diff --git a/openai-java-example/src/main/java/com/openai/example/ResponsesStructuredOutputsExample.java b/openai-java-example/src/main/java/com/openai/example/ResponsesStructuredOutputsExample.java new file mode 100644 index 000000000..9ef891831 --- /dev/null +++ b/openai-java-example/src/main/java/com/openai/example/ResponsesStructuredOutputsExample.java @@ -0,0 +1,73 @@ +package com.openai.example; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; +import com.openai.client.OpenAIClient; +import com.openai.client.okhttp.OpenAIOkHttpClient; +import com.openai.models.ChatModel; +import com.openai.models.responses.ResponseCreateParams; +import com.openai.models.responses.StructuredResponseCreateParams; +import java.util.List; + +public final class ResponsesStructuredOutputsExample { + + public static class Person { + @JsonPropertyDescription("The first name and surname of the person.") + public String name; + + public int birthYear; + + @JsonPropertyDescription("The year the person died, or 'present' if the person is living.") + public String deathYear; + + @Override + public String toString() { + return name + " (" + birthYear + '-' + deathYear + ')'; + } + } + + public static class Book { + public String title; + + public Person author; + + @JsonPropertyDescription("The year in which the book was first published.") + public int publicationYear; + + public String genre; + + @JsonIgnore + public String isbn; + + @Override + public String toString() { + return '"' + title + "\" (" + publicationYear + ") [" + genre + "] by " + author; + } + } + + public static class BookList { + public List books; + } + + private ResponsesStructuredOutputsExample() {} + + public static void main(String[] args) { + // Configures using one of: + // - The `OPENAI_API_KEY` environment variable + // - The `OPENAI_BASE_URL` and `AZURE_OPENAI_KEY` environment variables + OpenAIClient client = OpenAIOkHttpClient.fromEnv(); + + StructuredResponseCreateParams createParams = ResponseCreateParams.builder() + .input("List some famous late twentieth century novels.") + .text(BookList.class) + .model(ChatModel.GPT_4O) + .build(); + + client.responses().create(createParams).output().stream() + .flatMap(item -> item.message().stream()) + .flatMap(message -> message.content().stream()) + .flatMap(content -> content.outputText().stream()) + .flatMap(bookList -> bookList.books.stream()) + .forEach(book -> System.out.println(" - " + book)); + } +} diff --git a/openai-java-example/src/main/java/com/openai/example/StructuredOutputsExample.java b/openai-java-example/src/main/java/com/openai/example/StructuredOutputsExample.java index 9d3ce9daa..b4af99997 100644 --- a/openai-java-example/src/main/java/com/openai/example/StructuredOutputsExample.java +++ b/openai-java-example/src/main/java/com/openai/example/StructuredOutputsExample.java @@ -1,15 +1,54 @@ package com.openai.example; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; import com.openai.client.OpenAIClient; import com.openai.client.okhttp.OpenAIOkHttpClient; -import com.openai.core.JsonValue; import com.openai.models.ChatModel; -import com.openai.models.ResponseFormatJsonSchema; -import com.openai.models.ResponseFormatJsonSchema.JsonSchema; import com.openai.models.chat.completions.ChatCompletionCreateParams; -import java.util.Map; +import com.openai.models.chat.completions.StructuredChatCompletionCreateParams; +import java.util.List; public final class StructuredOutputsExample { + + public static class Person { + @JsonPropertyDescription("The first name and surname of the person.") + public String name; + + public int birthYear; + + @JsonPropertyDescription("The year the person died, or 'present' if the person is living.") + public String deathYear; + + @Override + public String toString() { + return name + " (" + birthYear + '-' + deathYear + ')'; + } + } + + public static class Book { + public String title; + + public Person author; + + @JsonPropertyDescription("The year in which the book was first published.") + public int publicationYear; + + public String genre; + + @JsonIgnore + public String isbn; + + @Override + public String toString() { + return '"' + title + "\" (" + publicationYear + ") [" + genre + "] by " + author; + } + } + + public static class BookList { + public List books; + } + private StructuredOutputsExample() {} public static void main(String[] args) { @@ -18,26 +57,16 @@ public static void main(String[] args) { // - The `OPENAI_BASE_URL` and `AZURE_OPENAI_KEY` environment variables OpenAIClient client = OpenAIOkHttpClient.fromEnv(); - // TODO: Update this once we support extracting JSON schemas from Java classes - JsonSchema.Schema schema = JsonSchema.Schema.builder() - .putAdditionalProperty("type", JsonValue.from("object")) - .putAdditionalProperty( - "properties", JsonValue.from(Map.of("employees", Map.of("items", Map.of("type", "string"))))) - .build(); - ChatCompletionCreateParams createParams = ChatCompletionCreateParams.builder() + StructuredChatCompletionCreateParams createParams = ChatCompletionCreateParams.builder() .model(ChatModel.GPT_4O_MINI) .maxCompletionTokens(2048) - .responseFormat(ResponseFormatJsonSchema.builder() - .jsonSchema(JsonSchema.builder() - .name("employee-list") - .schema(schema) - .build()) - .build()) - .addUserMessage("Who works at OpenAI?") + .responseFormat(BookList.class) + .addUserMessage("List some famous late twentieth century novels.") .build(); client.chat().completions().create(createParams).choices().stream() .flatMap(choice -> choice.message().content().stream()) - .forEach(System.out::println); + .flatMap(bookList -> bookList.books.stream()) + .forEach(book -> System.out.println(" - " + book)); } } diff --git a/openai-java-example/src/main/java/com/openai/example/StructuredOutputsAsyncExample.java b/openai-java-example/src/main/java/com/openai/example/StructuredOutputsRawAsyncExample.java similarity index 91% rename from openai-java-example/src/main/java/com/openai/example/StructuredOutputsAsyncExample.java rename to openai-java-example/src/main/java/com/openai/example/StructuredOutputsRawAsyncExample.java index a645f6cb0..f726e0cfe 100644 --- a/openai-java-example/src/main/java/com/openai/example/StructuredOutputsAsyncExample.java +++ b/openai-java-example/src/main/java/com/openai/example/StructuredOutputsRawAsyncExample.java @@ -9,8 +9,8 @@ import com.openai.models.chat.completions.ChatCompletionCreateParams; import java.util.Map; -public final class StructuredOutputsAsyncExample { - private StructuredOutputsAsyncExample() {} +public final class StructuredOutputsRawAsyncExample { + private StructuredOutputsRawAsyncExample() {} public static void main(String[] args) { // Configures using one of: @@ -18,7 +18,6 @@ public static void main(String[] args) { // - The `OPENAI_BASE_URL` and `AZURE_OPENAI_KEY` environment variables OpenAIClientAsync client = OpenAIOkHttpClientAsync.fromEnv(); - // TODO: Update this once we support extracting JSON schemas from Java classes JsonSchema.Schema schema = JsonSchema.Schema.builder() .putAdditionalProperty("type", JsonValue.from("object")) .putAdditionalProperty( diff --git a/openai-java-example/src/main/java/com/openai/example/StructuredOutputsRawExample.java b/openai-java-example/src/main/java/com/openai/example/StructuredOutputsRawExample.java new file mode 100644 index 000000000..3b9ff03ac --- /dev/null +++ b/openai-java-example/src/main/java/com/openai/example/StructuredOutputsRawExample.java @@ -0,0 +1,42 @@ +package com.openai.example; + +import com.openai.client.OpenAIClient; +import com.openai.client.okhttp.OpenAIOkHttpClient; +import com.openai.core.JsonValue; +import com.openai.models.ChatModel; +import com.openai.models.ResponseFormatJsonSchema; +import com.openai.models.ResponseFormatJsonSchema.JsonSchema; +import com.openai.models.chat.completions.ChatCompletionCreateParams; +import java.util.Map; + +public final class StructuredOutputsRawExample { + private StructuredOutputsRawExample() {} + + public static void main(String[] args) { + // Configures using one of: + // - The `OPENAI_API_KEY` environment variable + // - The `OPENAI_BASE_URL` and `AZURE_OPENAI_KEY` environment variables + OpenAIClient client = OpenAIOkHttpClient.fromEnv(); + + JsonSchema.Schema schema = JsonSchema.Schema.builder() + .putAdditionalProperty("type", JsonValue.from("object")) + .putAdditionalProperty( + "properties", JsonValue.from(Map.of("employees", Map.of("items", Map.of("type", "string"))))) + .build(); + ChatCompletionCreateParams createParams = ChatCompletionCreateParams.builder() + .model(ChatModel.GPT_4O_MINI) + .maxCompletionTokens(2048) + .responseFormat(ResponseFormatJsonSchema.builder() + .jsonSchema(JsonSchema.builder() + .name("employee-list") + .schema(schema) + .build()) + .build()) + .addUserMessage("Who works at OpenAI?") + .build(); + + client.chat().completions().create(createParams).choices().stream() + .flatMap(choice -> choice.message().content().stream()) + .forEach(System.out::println); + } +}