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-java
is actually a nearly fully modernized Kotlin library, so the nameopenai-java
is 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.gradle
to be a project file andlib/build.gradle
to 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? = json
toAudioResponseFormat? = AudioResponseFormat.json
- change
timestampGranularities?.value
totimestampGranularities
- 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/src
curl -o openapi-YYYYMMDD.yaml https://raw.githubusercontent.com/openai/openai-openapi/refs/heads/master/openapi.yaml
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
- Fix generated gradle files:
mv lib/build.gradle lib/build.gradle.kts
rm -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_progress
in nestedStatus
; undocumented value comes from the server
- add/keep
RealtimeConversationItemContentInner
- add/keep
audio
in nestedType
; undocumented value comes from the server
- add/keep
RealtimeResponse
- change/keep
maxOutputTokens
to typeRealtimeSessionMaxResponseOutputTokens
- add/keep
in_progress
in nestedStatus
; undocumented value comes from the server
- change/keep
RealtimeResponseCreateParams
- change/keep
maxResponseOutputTokens
to typeRealtimeSessionMaxResponseOutputTokens
- change/keep
RealtimeResponseCreateParamsConversation
- add/keep
enum class ... auto, none ...
- add/keep
- move
RealtimeResponseCreateParamsMaxResponseOutputTokens
to commonRealtimeSessionMaxResponseOutputTokens
This empty class would cause a runtime deserialization exception. - move
RealtimeResponseMaxOutputTokens
to commonRealtimeSessionMaxResponseOutputTokens
This 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
RealtimeSession
model
- add/keep javadoc
- change/keep type to
kotlin.String?
- change/keep
maxResponseOutputTokens
to typeRealtimeSessionMaxResponseOutputTokens
RealtimeSessionCreateRequest
- add/keep
@SerializeNull
- change/keep
maxResponseOutputTokens
to 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
model
to nestedModel
- add/keep nested
RealtimeSessionCreateRequestTurnDetection
- add/keep nested
enum class Type server_vad ...
- change/keep
type
to nestedType
- add/keep nested
RealtimeSessionCreateResponse
- change/keep
maxResponseOutputTokens
to 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