feat: Add audio type according to 2025-03-26 spec (#68)
* feat: Add audio type according to 2025-03-26 spec * chore: update documentation * feat: add unit test * chore: commit api dump * feat: Add audio type according to 2025-03-26 spec * chore: update documentation * feat: add unit test * chore: rebase and commit api dump --------- Co-authored-by: Leonid Stashevsky <e5l@users.noreply.github.com>
This commit is contained in:
parent
c582a8c442
commit
9f00f22596
3 changed files with 119 additions and 29 deletions
|
|
@ -897,10 +897,10 @@ public sealed interface PromptMessageContent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Represents prompt message content that is either text or an image.
|
||||
* Represents prompt message content that is either text, image or audio.
|
||||
*/
|
||||
@Serializable(with = PromptMessageContentTextOrImagePolymorphicSerializer::class)
|
||||
public sealed interface PromptMessageContentTextOrImage : PromptMessageContent
|
||||
@Serializable(with = PromptMessageContentMultimodalPolymorphicSerializer::class)
|
||||
public sealed interface PromptMessageContentMultimodal : PromptMessageContent
|
||||
|
||||
/**
|
||||
* Text provided to or from an LLM.
|
||||
|
|
@ -911,7 +911,7 @@ public data class TextContent(
|
|||
* The text content of the message.
|
||||
*/
|
||||
val text: String? = null,
|
||||
) : PromptMessageContentTextOrImage {
|
||||
) : PromptMessageContentMultimodal {
|
||||
override val type: String = TYPE
|
||||
|
||||
public companion object {
|
||||
|
|
@ -933,7 +933,7 @@ public data class ImageContent(
|
|||
* The MIME type of the image. Different providers may support different image types.
|
||||
*/
|
||||
val mimeType: String,
|
||||
) : PromptMessageContentTextOrImage {
|
||||
) : PromptMessageContentMultimodal {
|
||||
override val type: String = TYPE
|
||||
|
||||
public companion object {
|
||||
|
|
@ -942,12 +942,35 @@ public data class ImageContent(
|
|||
}
|
||||
|
||||
/**
|
||||
* An image provided to or from an LLM.
|
||||
* Audio provided to or from an LLM.
|
||||
*/
|
||||
@Serializable
|
||||
public data class AudioContent(
|
||||
/**
|
||||
* The base64-encoded audio data.
|
||||
*/
|
||||
val data: String,
|
||||
|
||||
/**
|
||||
* The MIME type of the audio. Different providers may support different audio types.
|
||||
*/
|
||||
val mimeType: String,
|
||||
) : PromptMessageContentMultimodal {
|
||||
override val type: String = TYPE
|
||||
|
||||
public companion object {
|
||||
public const val TYPE: String = "audio"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unknown content provided to or from an LLM.
|
||||
*/
|
||||
@Serializable
|
||||
public data class UnknownContent(
|
||||
override val type: String,
|
||||
) : PromptMessageContentTextOrImage
|
||||
) : PromptMessageContentMultimodal
|
||||
|
||||
/**
|
||||
* The contents of a resource, embedded into a prompt or tool call result.
|
||||
|
|
@ -1217,7 +1240,7 @@ public class ModelPreferences(
|
|||
@Serializable
|
||||
public data class SamplingMessage(
|
||||
val role: Role,
|
||||
val content: PromptMessageContentTextOrImage,
|
||||
val content: PromptMessageContentMultimodal,
|
||||
)
|
||||
|
||||
/**
|
||||
|
|
@ -1299,7 +1322,7 @@ public data class CreateMessageResult(
|
|||
*/
|
||||
val stopReason: StopReason? = null,
|
||||
val role: Role,
|
||||
val content: PromptMessageContentTextOrImage,
|
||||
val content: PromptMessageContentMultimodal,
|
||||
override val _meta: JsonObject = EmptyJsonObject,
|
||||
) : ClientResult
|
||||
|
||||
|
|
|
|||
|
|
@ -80,17 +80,19 @@ internal object PromptMessageContentPolymorphicSerializer :
|
|||
ImageContent.TYPE -> ImageContent.serializer()
|
||||
TextContent.TYPE -> TextContent.serializer()
|
||||
EmbeddedResource.TYPE -> EmbeddedResource.serializer()
|
||||
AudioContent.TYPE -> AudioContent.serializer()
|
||||
else -> UnknownContent.serializer()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object PromptMessageContentTextOrImagePolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<PromptMessageContentTextOrImage>(PromptMessageContentTextOrImage::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<PromptMessageContentTextOrImage> {
|
||||
internal object PromptMessageContentMultimodalPolymorphicSerializer :
|
||||
JsonContentPolymorphicSerializer<PromptMessageContentMultimodal>(PromptMessageContentMultimodal::class) {
|
||||
override fun selectDeserializer(element: JsonElement): DeserializationStrategy<PromptMessageContentMultimodal> {
|
||||
return when (element.jsonObject.getValue("type").jsonPrimitive.content) {
|
||||
ImageContent.TYPE -> ImageContent.serializer()
|
||||
TextContent.TYPE -> TextContent.serializer()
|
||||
AudioContent.TYPE -> AudioContent.serializer()
|
||||
else -> UnknownContent.serializer()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
src/commonTest/kotlin/AudioContentSerializationTest.kt
Normal file
34
src/commonTest/kotlin/AudioContentSerializationTest.kt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
package io.modelcontextprotocol.kotlin.sdk
|
||||
|
||||
import io.kotest.assertions.json.shouldEqualJson
|
||||
import io.modelcontextprotocol.kotlin.sdk.shared.McpJson
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class AudioContentSerializationTest {
|
||||
|
||||
private val audioContentJson = """
|
||||
{
|
||||
"data": "base64-encoded-audio-data",
|
||||
"mimeType": "audio/wav",
|
||||
"type": "audio"
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
private val audioContent = AudioContent(
|
||||
data = "base64-encoded-audio-data",
|
||||
mimeType = "audio/wav"
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `should serialize audio content`() {
|
||||
McpJson.encodeToString(audioContent) shouldEqualJson audioContentJson
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `should deserialize audio content`() {
|
||||
val content = McpJson.decodeFromString<AudioContent>(audioContentJson)
|
||||
assertEquals(expected = audioContent, actual = content)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue