OpenAI OpenAPI Specification - Kotlin
From https://github.com/openai/openai-openapi/blob/master/openapi.yaml
NOTES:
- There is https://github.com/openai/openai-java, which OpenAI describes as
"The official Java library for the OpenAI API", but:
- That "official" library lags behind https://github.com/openai/openai-openapi/blob/master/openapi.yaml
For example, as of 2025/02/12 is is STILL lacking OpenAI's Realtime API (https://platform.openai.com/docs/api-reference/realtime), which is my main use case. openai-javais actually a nearly fully modernized Kotlin library, so the nameopenai-javais legacy;
it really should be namedopenai-kotlin.
- That "official" library lags behind https://github.com/openai/openai-openapi/blob/master/openapi.yaml
- I was initially tempted to inflate this repo to contain multiple openapi-generator generated languages, but for now I am limiting it to Kotlin.
- openapi-generator has >4k open Issues:
https://github.com/OpenAPITools/openapi-generator/issues
So, no promises about the quality of its output.
Maybe one day I will open a PR to auto-generate some of the changes I made manually.
Requirements:
- OpenAPI Generator: https://openapi-generator.tech/docs/installation
Optional:
curl -o openapi-YYYYMMDD.yaml https://raw.githubusercontent.com/openai/openai-openapi/refs/heads/master/openapi.yaml
You don't have to do this.
openapi-generator supports fetching the specification directly from a url.
I prefer to save a snapshot of the specification that was used for the generation.
time openapi-generator generate -i openapi-YYYYMMDD.yaml -g kotlin -o ./lib --skip-validate-spec --additional-properties=artifactId=openai-kotlin-client,artifactVersion=0.0.1,groupId=com.openai,packageName=com.openai
(< 5 seconds on MacBook Pro M4 Pro)cp lib/build.gradle .mv lib/gradle* lib/settings.gradle .echo -e "\ninclude(\":lib\")" >> settings.gradle- Edit
build.gradleto be a project file andlib/build.gradleto be a module file. chmod +x ./gradlew./gradlew build
(< 20 seconds on MacBook Pro M4 Pro to [eventually; see "Changes"] successfully compile from clean)
All of this is also shown in the openai-kotlin-client.sh file.
At this point, the build will actually fail.
I had to make some manual changes in order to get it to compile successfully:
- AudioApi.kt:
- change
AudioResponseFormat? = jsontoAudioResponseFormat? = AudioResponseFormat.json - change
timestampGranularities?.valuetotimestampGranularities
- change
- remove
data(data class ...->class ...) in:- CreateAssistantRequestToolResourcesFileSearch.kt
- CreateThreadRequestToolResourcesFileSearch.kt
This just got it to COMPILE successfully!
I had to make further changes in order to get it to RUN successfully.
All of my changes can be seen at:
https://github.com/swooby/openai-openapi-kotlin/pull/1/files
When a new spec comes out:
- Make sure to start from a fresh/stashed checkout.
rm -r ./lib/srccurl -o openapi-YYYYMMDD.yaml https://raw.githubusercontent.com/openai/openai-openapi/refs/heads/master/openapi.yamlopenapi-generator generate -i openapi-YYYYMMDD.yaml -g kotlin -o ./lib --skip-validate-spec --additional-properties=artifactId=openai-kotlin-client,artifactVersion=0.0.1,groupId=com.openai,packageName=com.openai- Fix generated gradle files:
mv lib/build.gradle lib/build.gradle.ktsrm -f ./gradle && mv lib/gradle* .mv lib/settings.gradle ./settings.gradle.kts- Compare/Review with the settings.gradle and build.gradle files.
gradle*: probably discard all changessettings.gradle.kts: probably discard all changeslib/build.gradle.kts: probably discard all changes
- While you are here, update any dependencies in
gradle/libs.versions.toml
- Consistently format all generated code with
./gradlew spotlessApply - Fix generated code compiler errors:
TODO: Open an OpenAPI or OpenAI bug on these...apis/AudioApi- add/keep
AudioResponseFormat.json - add/keep
timestampGranularities?.value
- add/keep
models/CreateAssistantRequestToolResourcesFileSearch: keep non-data class
(compiler error to have data class with no constructor parameters)models/CreateThreadRequestToolResourcesFileSearch: keep non-data class
(compiler error to have data class with no constructor parameters)
- Review each changed file, especially ones that show as modified in:
https://github.com/swooby/openai-openapi-kotlin/pull/1/filesapis&docs: probably keep all changesinfrastructure:ApiClient.kt: probably discard all changesBigDecimalAdapter.kt: probably discard all changesBigIntegerAdapter.kt: probably discard all changesSerializer.kt: probably discard all changes
models: probably keep all changes except...Realtime*files:
(This can get a little complicated...)RealtimeClientEvent*: Keep alltype: RealtimeClientEvent*.Type = RealtimeClientEvent*.Type....one-line assignments
These help a lot to simplify sending client events.RealtimeConversationItem- add/keep
in_progressin nestedStatus; undocumented value comes from the server
- add/keep
RealtimeConversationItemContentInner- add/keep
audioin nestedType; undocumented value comes from the server
- add/keep
RealtimeResponse- change/keep
maxOutputTokensto typeRealtimeSessionMaxResponseOutputTokens - add/keep
in_progressin nestedStatus; undocumented value comes from the server
- change/keep
RealtimeResponseCreateParams- change/keep
maxResponseOutputTokensto typeRealtimeSessionMaxResponseOutputTokens
- change/keep
RealtimeResponseCreateParamsConversation- add/keep
enum class ... auto, none ...
- add/keep
- move
RealtimeResponseCreateParamsMaxResponseOutputTokensto commonRealtimeSessionMaxResponseOutputTokens
This empty class would cause a runtime deserialization exception. - move
RealtimeResponseMaxOutputTokensto commonRealtimeSessionMaxResponseOutputTokensThis empty class would cause a runtime deserialization exception. RealtimeServerEventConversationItemCreated- add/keep nullable
previousItemId; null value comes from the server
- add/keep nullable
RealtimeServerEventInputAudioBufferCommitted:- add/keep nullable
previousItemId; null value comes from the server
- add/keep nullable
RealtimeSessionmodel- add/keep javadoc
- change/keep type to
kotlin.String?
- change/keep
maxResponseOutputTokensto typeRealtimeSessionMaxResponseOutputTokens
RealtimeSessionCreateRequest- add/keep
@SerializeNull - change/keep
maxResponseOutputTokensto typeRealtimeSessionMaxResponseOutputTokens - nested
enum class Model- change/keep javadoc
- change/keep
gpt-4o-realtime-preview ...simplification;
The generated names leave outgpt-4o-.
- add/keep
RealtimeSessionCreateRequestInputAudioTranscription- add/keep nested
enum class Model whisper-1 ... - change/keep
modelto nestedModel
- add/keep nested
RealtimeSessionCreateRequestTurnDetection- add/keep nested
enum class Type server_vad ... - change/keep
typeto nestedType
- add/keep nested
RealtimeSessionCreateResponse- change/keep
maxResponseOutputTokensto typeRealtimeSessionMaxResponseOutputTokens
- change/keep
- restore/reset/keep
RealtimeSessionMaxResponseOutputTokens - delete
RealtimeSessionModel
This empty class would cause a runtime deserialization exception.
test: probably keep all changes except...- revert
RealtimeResponseCreateParamsMaxResponseOutputTokensTest
detected as a rename fromRealtimeSessionMaxResponseOutputTokensTest - delete
RealtimeResponseMaxOutputTokensTest - delete
RealtimeSessionModelTest
- revert