diff --git a/CHANGELOG.md b/CHANGELOG.md index 0cdd1f7f5..854e5126a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This list is not intended to be all-encompassing - it will document major and breaking API changes with their rationale when appropriate. Given version `A.B.C.D`, breaking changes are to be expected in version number increments where changes in the `A` or `B` sections: +### v5.24.0.0 +- **http4k-connect-*** - Upgrade dependencies including Kotlin to 2.0.20 +- **http4k-connect-ai-openai*** - [Breaking] tightened up types for completion requests. + ### v5.23.0.0 - **http4k-connect-*** - Upgrade dependencies including Kotlin to 2.0.20 - **http4k-connect-ai-azure*** - Add new operations. diff --git a/ai/openai/client/src/main/kotlin/org/http4k/connect/openai/action/ChatCompletion.kt b/ai/openai/client/src/main/kotlin/org/http4k/connect/openai/action/ChatCompletion.kt index 8d56863df..cb8e6c70b 100644 --- a/ai/openai/client/src/main/kotlin/org/http4k/connect/openai/action/ChatCompletion.kt +++ b/ai/openai/client/src/main/kotlin/org/http4k/connect/openai/action/ChatCompletion.kt @@ -64,6 +64,21 @@ data class ChatCompletion( stream = stream ) + constructor(model: ModelName, message: Message, max_tokens: Int = 16, stream: Boolean = true) : this( + model, + listOf(message), + max_tokens = max_tokens, + temperature = 1.0, + top_p = 1.0, + n = 1, + stop = null, + presence_penalty = 0.0, + frequency_penalty = 0.0, + logit_bias = null, + user = null, + stream = stream + ) + init { require(tools == null || tools.isNotEmpty()) { "Tools cannot be empty" } } @@ -92,21 +107,42 @@ sealed class ResponseFormat { data class JsonSchema(val strict: Boolean, val json_schema: Map) : ResponseFormat() } - @JsonSerializable data class Message( val role: Role?, - val content: List, + val content: List? = null, val name: User? = null, + val refusal: String? = null, val tool_calls: List? = null ) { + @Deprecated("Use relevant companion constructor instead") constructor( role: Role, text: String, name: User? = null, tool_calls: List? = null ) : - this(role, listOf(MessageContent(ContentType.text, text)), name, tool_calls) + this(role, listOf(MessageContent(ContentType.text, text)), name, null, tool_calls) + + companion object { + fun User(content: String, name: User? = null) = User(listOf(MessageContent(ContentType.text, content)), name) + fun User(content: List, name: User? = null) = Message(Role.User, content, name, null) + + fun System(content: String, name: User? = null) = + System(listOf(MessageContent(ContentType.text, content)), name) + + fun System(content: List, name: User? = null) = Message(Role.System, content, name) + + fun Assistant(content: String, name: User? = null, refusal: String? = null) = + Assistant(listOf(MessageContent(ContentType.text, content)), name, refusal) + + fun Assistant(content: List, name: User? = null, refusal: String? = null) = + Message(Role.Assistant, content, name, refusal) + + @JvmName("AssistantToolCalls") + fun Assistant(tool_calls: List, name: User? = null, refusal: String? = null) = + Message(Role.Assistant, null, name, refusal, tool_calls) + } } @JsonSerializable diff --git a/ai/openai/client/src/test/kotlin/org/http4k/connect/openai/OpenAIContract.kt b/ai/openai/client/src/test/kotlin/org/http4k/connect/openai/OpenAIContract.kt index f64a23d7f..07535ecba 100644 --- a/ai/openai/client/src/test/kotlin/org/http4k/connect/openai/OpenAIContract.kt +++ b/ai/openai/client/src/test/kotlin/org/http4k/connect/openai/OpenAIContract.kt @@ -39,8 +39,8 @@ interface OpenAIContract { val responses = openAi.chatCompletion( ModelName.GPT3_5, listOf( - Message(System, "You are Leonardo Da Vinci"), - Message(User, "What is your favourite colour?") + Message.System("You are Leonardo Da Vinci"), + Message.User("What is your favourite colour?") ), 1000, stream = false @@ -55,8 +55,8 @@ interface OpenAIContract { val responses = openAi.chatCompletion( ModelName.GPT3_5, listOf( - Message(System, "You are Leonardo Da Vinci"), - Message(User, "What is your favourite colour?") + Message.System("You are Leonardo Da Vinci"), + Message.User("What is your favourite colour?") ), 1000, stream = true diff --git a/ai/openai/fake/src/examples/kotlin/interacting-with-openai.kt b/ai/openai/fake/src/examples/kotlin/interacting-with-openai.kt index 7f994887a..43c8af67b 100644 --- a/ai/openai/fake/src/examples/kotlin/interacting-with-openai.kt +++ b/ai/openai/fake/src/examples/kotlin/interacting-with-openai.kt @@ -18,7 +18,7 @@ fun main() { openai.chatCompletion( ModelName.GPT3_5, listOf( - Message(User, "Explain pythagoras's theorem to a 5 year old child"), + Message.User("Explain pythagoras's theorem to a 5 year old child") ), 1000, false diff --git a/ai/openai/fake/src/examples/kotlin/using the fake.kt b/ai/openai/fake/src/examples/kotlin/using the fake.kt index 22a782626..6bd9cadf5 100644 --- a/ai/openai/fake/src/examples/kotlin/using the fake.kt +++ b/ai/openai/fake/src/examples/kotlin/using the fake.kt @@ -30,7 +30,7 @@ fun main() { // get a chat completion openai - .chatCompletion(ModelName.GPT3_5, listOf(Message(User, "good afternoon")), 1000, true) + .chatCompletion(ModelName.GPT3_5, listOf(Message.User("good afternoon")), 1000, true) .onFailure { error(it) } .toList() .first() diff --git a/ai/openai/fake/src/main/kotlin/org/http4k/connect/openai/ChatCompletionGenerator.kt b/ai/openai/fake/src/main/kotlin/org/http4k/connect/openai/ChatCompletionGenerator.kt index bb4317cc8..2ff728093 100644 --- a/ai/openai/fake/src/main/kotlin/org/http4k/connect/openai/ChatCompletionGenerator.kt +++ b/ai/openai/fake/src/main/kotlin/org/http4k/connect/openai/ChatCompletionGenerator.kt @@ -21,9 +21,9 @@ fun interface ChatCompletionGenerator : (ChatCompletion) -> List { val ChatCompletionGenerator.Companion.ReverseInput get() = ChatCompletionGenerator { req -> req.messages.flatMap { m -> - m.content.mapIndexed { i, content -> + m.content?.mapIndexed { i, content -> Choice(i, ChoiceDetail(Role.System, content.text?.reversed() ?: "", null), null, stop) - } + } ?: emptyList() } } @@ -39,7 +39,7 @@ fun ChatCompletionGenerator.Companion.LoremIpsum(random: Random = Random(0)) = C */ val ChatCompletionGenerator.Companion.Echo get() = ChatCompletionGenerator { req -> - req.choices(req.messages.first { it.role == Role.User }.content.first().text ?: "") + req.choices(req.messages.first { it.role == Role.User }.content?.first()?.text ?: "") } private fun ChatCompletion.choices(msg: String) = (if (stream) msg.split(" ").map { "$it " } else listOf(msg)) diff --git a/versions.properties b/versions.properties index 7b0c2b2f0..944251fb0 100644 --- a/versions.properties +++ b/versions.properties @@ -11,13 +11,13 @@ plugin.com.github.kt3k.coveralls=2.12.2 -plugin.com.google.devtools.ksp=2.0.20-1.0.24 +plugin.com.google.devtools.ksp=2.0.20-1.0.25 plugin.de.fayard.buildSrcLibs=0.60.5 plugin.com.github.davidmc24.gradle.plugin.avro=1.9.1 -version.com.google.devtools.ksp..symbol-processing-api=2.0.20-1.0.24 +version.com.google.devtools.ksp..symbol-processing-api=2.0.20-1.0.25 version.com.amazonaws..aws-lambda-java-events=3.13.0 @@ -29,9 +29,9 @@ version.com.zaxxer..HikariCP=5.1.0 version.dev.forkhandles..forkhandles-bom=2.20.0.0 -version.dev.langchain4j..langchain4j=0.33.0 +version.dev.langchain4j..langchain4j=0.34.0 -version.http4k=5.29.0.0 +version.http4k=5.30.0.0 version.joda-time..joda-time=2.12.7 @@ -55,6 +55,7 @@ version.jetbrains.exposed=0.41.1 ## # available=0.51.1 ## # available=0.52.0 ## # available=0.53.0 +## # available=0.54.0 version.org.apache.avro..avro=1.12.0 @@ -86,12 +87,12 @@ version.se.ansman.kotshi..api=3.0.0 version.se.ansman.kotshi..compiler=3.0.0 -version.software.amazon.awssdk..bom=2.27.12 +version.software.amazon.awssdk..bom=2.27.21 version.com.nimbusds..nimbus-jose-jwt=9.40 -version.dev.langchain4j..langchain4j-core=0.33.0 +version.dev.langchain4j..langchain4j-core=0.34.0 -version.software.amazon.awssdk..s3=2.27.12 +version.software.amazon.awssdk..s3=2.27.21 -version.software.amazon.awssdk..sqs=2.27.12 +version.software.amazon.awssdk..sqs=2.27.21