From 429ffb0e55ec9889718f0f0128f1ed6cddcd810c Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Wed, 9 Apr 2025 00:57:56 +0800 Subject: [PATCH 1/8] feat: Add audio type according to 2025-03-26 spec --- .../modelcontextprotocol/kotlin/sdk/types.kt | 37 +++++++++++++++---- .../kotlin/sdk/types.util.kt | 8 ++-- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt index d2fa2cb2..acf3b876 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -886,8 +886,8 @@ public sealed interface PromptMessageContent { /** * Represents prompt message content that is either text or an image. */ -@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. @@ -898,7 +898,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 { @@ -920,7 +920,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 { @@ -928,13 +928,36 @@ public data class ImageContent( } } +/** + * 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" + } +} + + /** * An image 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. @@ -1204,7 +1227,7 @@ public class ModelPreferences( @Serializable public data class SamplingMessage( val role: Role, - val content: PromptMessageContentTextOrImage, + val content: PromptMessageContentMultimodal, ) /** @@ -1286,7 +1309,7 @@ public data class CreateMessageResult( */ val stopReason: StopReason? = null, val role: Role, - val content: PromptMessageContentTextOrImage, + val content: PromptMessageContentMultimodal, override val _meta: JsonObject = EmptyJsonObject, ) : ClientResult diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt index cb7b1005..53f21d0e 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt @@ -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::class) { - override fun selectDeserializer(element: JsonElement): DeserializationStrategy { +internal object PromptMessageContentMultimodalPolymorphicSerializer : + JsonContentPolymorphicSerializer(PromptMessageContentMultimodal::class) { + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { return when (element.jsonObject.getValue("type").jsonPrimitive.content) { ImageContent.TYPE -> ImageContent.serializer() TextContent.TYPE -> TextContent.serializer() + AudioContent.TYPE -> AudioContent.serializer() else -> UnknownContent.serializer() } } From df57c946943c12102ffefd9967eb9b52664bfc03 Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Thu, 10 Apr 2025 08:07:42 +0800 Subject: [PATCH 2/8] chore: update documentation --- .../kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt index acf3b876..576673f8 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -884,7 +884,7 @@ 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 = PromptMessageContentMultimodalPolymorphicSerializer::class) public sealed interface PromptMessageContentMultimodal : PromptMessageContent @@ -952,7 +952,7 @@ public data class AudioContent( /** - * An image provided to or from an LLM. + * Unknown content provided to or from an LLM. */ @Serializable public data class UnknownContent( From 95a28575775455900883e9c48889ad9a7dfa79cb Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Sat, 12 Apr 2025 15:23:15 +0800 Subject: [PATCH 3/8] feat: add unit test --- .../kotlin/AudioContentSerializationTest.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/commonTest/kotlin/AudioContentSerializationTest.kt diff --git a/src/commonTest/kotlin/AudioContentSerializationTest.kt b/src/commonTest/kotlin/AudioContentSerializationTest.kt new file mode 100644 index 00000000..6745972c --- /dev/null +++ b/src/commonTest/kotlin/AudioContentSerializationTest.kt @@ -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(audioContentJson) + assertEquals(expected = audioContent, actual = content) + } +} \ No newline at end of file From ba6e2e185b50692335afaf37364b7a23addadda0 Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Wed, 30 Apr 2025 12:54:28 +0800 Subject: [PATCH 4/8] chore: commit api dump --- api/kotlin-sdk.api | 65 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/api/kotlin-sdk.api b/api/kotlin-sdk.api index 4f0b20c4..7be90746 100644 --- a/api/kotlin-sdk.api +++ b/api/kotlin-sdk.api @@ -1,3 +1,34 @@ +public final class io/modelcontextprotocol/kotlin/sdk/AudioContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/AudioContent$Companion; + public static final field TYPE Ljava/lang/String; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/AudioContent;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public fun equals (Ljava/lang/Object;)Z + public final fun getData ()Ljava/lang/String; + public final fun getMimeType ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public synthetic class io/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/AudioContent;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class io/modelcontextprotocol/kotlin/sdk/AudioContent$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public final class io/modelcontextprotocol/kotlin/sdk/BlobResourceContents : io/modelcontextprotocol/kotlin/sdk/ResourceContents { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/BlobResourceContents$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V @@ -413,17 +444,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/CreateMessageRequest$Inclu public final class io/modelcontextprotocol/kotlin/sdk/CreateMessageResult : io/modelcontextprotocol/kotlin/sdk/ClientResult { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult$Companion; - public fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;)V - public synthetic fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;)V + public synthetic fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/StopReason; public final fun component3 ()Lio/modelcontextprotocol/kotlin/sdk/Role; - public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; + public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; public final fun component5 ()Lkotlinx/serialization/json/JsonObject; - public final fun copy (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; - public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; + public final fun copy (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; public fun equals (Ljava/lang/Object;)Z - public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; + public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; public final fun getModel ()Ljava/lang/String; public final fun getRole ()Lio/modelcontextprotocol/kotlin/sdk/Role; public final fun getStopReason ()Lio/modelcontextprotocol/kotlin/sdk/StopReason; @@ -663,7 +694,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/GetPromptResult$Companion public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public final class io/modelcontextprotocol/kotlin/sdk/ImageContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage { +public final class io/modelcontextprotocol/kotlin/sdk/ImageContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ImageContent$Companion; public static final field TYPE Ljava/lang/String; public fun (Ljava/lang/String;Ljava/lang/String;)V @@ -1665,11 +1696,11 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContent$Compa public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public abstract interface class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage : io/modelcontextprotocol/kotlin/sdk/PromptMessageContent { - public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage$Companion; +public abstract interface class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal : io/modelcontextprotocol/kotlin/sdk/PromptMessageContent { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal$Companion; } -public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage$Companion { +public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } @@ -2075,13 +2106,13 @@ public final class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotificati public final class io/modelcontextprotocol/kotlin/sdk/SamplingMessage { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage$Companion; - public fun (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;)V + public fun (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Role; - public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; - public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; - public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; + public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; + public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; public fun equals (Ljava/lang/Object;)Z - public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; + public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; public final fun getRole ()Lio/modelcontextprotocol/kotlin/sdk/Role; public fun hashCode ()I public fun toString ()Ljava/lang/String; @@ -2340,7 +2371,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/SubscribeRequest$Companion public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public final class io/modelcontextprotocol/kotlin/sdk/TextContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage { +public final class io/modelcontextprotocol/kotlin/sdk/TextContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/TextContent$Companion; public static final field TYPE Ljava/lang/String; public fun ()V @@ -2492,7 +2523,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/TypesKt { public static final fun getSUPPORTED_PROTOCOL_VERSIONS ()[Ljava/lang/String; } -public final class io/modelcontextprotocol/kotlin/sdk/UnknownContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage { +public final class io/modelcontextprotocol/kotlin/sdk/UnknownContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/UnknownContent$Companion; public fun (Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String; From bde6433d6267d5009075a1bf15389f129fb357cd Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Wed, 9 Apr 2025 00:57:56 +0800 Subject: [PATCH 5/8] feat: Add audio type according to 2025-03-26 spec --- .../modelcontextprotocol/kotlin/sdk/types.kt | 37 +++++++++++++++---- .../kotlin/sdk/types.util.kt | 8 ++-- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt index c69d2d27..0120df03 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -899,8 +899,8 @@ public sealed interface PromptMessageContent { /** * Represents prompt message content that is either text or an image. */ -@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 { @@ -941,13 +941,36 @@ public data class ImageContent( } } +/** + * 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" + } +} + + /** * An image 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 diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt index e93abde3..8a4dcd25 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.util.kt @@ -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::class) { - override fun selectDeserializer(element: JsonElement): DeserializationStrategy { +internal object PromptMessageContentMultimodalPolymorphicSerializer : + JsonContentPolymorphicSerializer(PromptMessageContentMultimodal::class) { + override fun selectDeserializer(element: JsonElement): DeserializationStrategy { return when (element.jsonObject.getValue("type").jsonPrimitive.content) { ImageContent.TYPE -> ImageContent.serializer() TextContent.TYPE -> TextContent.serializer() + AudioContent.TYPE -> AudioContent.serializer() else -> UnknownContent.serializer() } } From b5fb767403d18bc54a9be75717dcacd324018fae Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Thu, 10 Apr 2025 08:07:42 +0800 Subject: [PATCH 6/8] chore: update documentation --- .../kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt index 0120df03..e8606a84 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -897,7 +897,7 @@ 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 = PromptMessageContentMultimodalPolymorphicSerializer::class) public sealed interface PromptMessageContentMultimodal : PromptMessageContent @@ -965,7 +965,7 @@ public data class AudioContent( /** - * An image provided to or from an LLM. + * Unknown content provided to or from an LLM. */ @Serializable public data class UnknownContent( From 711bb59199a2995b7d79c32d5dcaa6f893042318 Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Sat, 12 Apr 2025 15:23:15 +0800 Subject: [PATCH 7/8] feat: add unit test --- .../kotlin/AudioContentSerializationTest.kt | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/commonTest/kotlin/AudioContentSerializationTest.kt diff --git a/src/commonTest/kotlin/AudioContentSerializationTest.kt b/src/commonTest/kotlin/AudioContentSerializationTest.kt new file mode 100644 index 00000000..6745972c --- /dev/null +++ b/src/commonTest/kotlin/AudioContentSerializationTest.kt @@ -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(audioContentJson) + assertEquals(expected = audioContent, actual = content) + } +} \ No newline at end of file From f6cd99fbaddce2433101bfd1bf5a61d7eb555147 Mon Sep 17 00:00:00 2001 From: SeanChinJunKai Date: Wed, 30 Apr 2025 15:49:49 +0800 Subject: [PATCH 8/8] chore: rebase and commit api dump --- api/kotlin-sdk.api | 65 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 17 deletions(-) diff --git a/api/kotlin-sdk.api b/api/kotlin-sdk.api index cd74e0cd..a82600a8 100644 --- a/api/kotlin-sdk.api +++ b/api/kotlin-sdk.api @@ -1,3 +1,34 @@ +public final class io/modelcontextprotocol/kotlin/sdk/AudioContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/AudioContent$Companion; + public static final field TYPE Ljava/lang/String; + public fun (Ljava/lang/String;Ljava/lang/String;)V + public final fun component1 ()Ljava/lang/String; + public final fun component2 ()Ljava/lang/String; + public final fun copy (Ljava/lang/String;Ljava/lang/String;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/AudioContent;Ljava/lang/String;Ljava/lang/String;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public fun equals (Ljava/lang/Object;)Z + public final fun getData ()Ljava/lang/String; + public final fun getMimeType ()Ljava/lang/String; + public fun getType ()Ljava/lang/String; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + +public synthetic class io/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer : kotlinx/serialization/internal/GeneratedSerializer { + public static final field INSTANCE Lio/modelcontextprotocol/kotlin/sdk/AudioContent$$serializer; + public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; + public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lio/modelcontextprotocol/kotlin/sdk/AudioContent; + public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; + public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; + public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lio/modelcontextprotocol/kotlin/sdk/AudioContent;)V + public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V + public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; +} + +public final class io/modelcontextprotocol/kotlin/sdk/AudioContent$Companion { + public final fun serializer ()Lkotlinx/serialization/KSerializer; +} + public final class io/modelcontextprotocol/kotlin/sdk/BlobResourceContents : io/modelcontextprotocol/kotlin/sdk/ResourceContents { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/BlobResourceContents$Companion; public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V @@ -413,17 +444,17 @@ public final class io/modelcontextprotocol/kotlin/sdk/CreateMessageRequest$Inclu public final class io/modelcontextprotocol/kotlin/sdk/CreateMessageResult : io/modelcontextprotocol/kotlin/sdk/ClientResult { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult$Companion; - public fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;)V - public synthetic fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;)V + public synthetic fun (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/StopReason; public final fun component3 ()Lio/modelcontextprotocol/kotlin/sdk/Role; - public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; + public final fun component4 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; public final fun component5 ()Lkotlinx/serialization/json/JsonObject; - public final fun copy (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; - public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; + public final fun copy (Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult;Ljava/lang/String;Lio/modelcontextprotocol/kotlin/sdk/StopReason;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CreateMessageResult; public fun equals (Ljava/lang/Object;)Z - public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; + public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; public final fun getModel ()Ljava/lang/String; public final fun getRole ()Lio/modelcontextprotocol/kotlin/sdk/Role; public final fun getStopReason ()Lio/modelcontextprotocol/kotlin/sdk/StopReason; @@ -663,7 +694,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/GetPromptResult$Companion public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public final class io/modelcontextprotocol/kotlin/sdk/ImageContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage { +public final class io/modelcontextprotocol/kotlin/sdk/ImageContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/ImageContent$Companion; public static final field TYPE Ljava/lang/String; public fun (Ljava/lang/String;Ljava/lang/String;)V @@ -1669,11 +1700,11 @@ public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContent$Compa public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public abstract interface class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage : io/modelcontextprotocol/kotlin/sdk/PromptMessageContent { - public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage$Companion; +public abstract interface class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal : io/modelcontextprotocol/kotlin/sdk/PromptMessageContent { + public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal$Companion; } -public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage$Companion { +public final class io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal$Companion { public final fun serializer ()Lkotlinx/serialization/KSerializer; } @@ -2079,13 +2110,13 @@ public final class io/modelcontextprotocol/kotlin/sdk/RootsListChangedNotificati public final class io/modelcontextprotocol/kotlin/sdk/SamplingMessage { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage$Companion; - public fun (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;)V + public fun (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;)V public final fun component1 ()Lio/modelcontextprotocol/kotlin/sdk/Role; - public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; - public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; - public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; + public final fun component2 ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; + public final fun copy (Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; + public static synthetic fun copy$default (Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage;Lio/modelcontextprotocol/kotlin/sdk/Role;Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/SamplingMessage; public fun equals (Ljava/lang/Object;)Z - public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage; + public final fun getContent ()Lio/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal; public final fun getRole ()Lio/modelcontextprotocol/kotlin/sdk/Role; public fun hashCode ()I public fun toString ()Ljava/lang/String; @@ -2344,7 +2375,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/SubscribeRequest$Companion public final fun serializer ()Lkotlinx/serialization/KSerializer; } -public final class io/modelcontextprotocol/kotlin/sdk/TextContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage { +public final class io/modelcontextprotocol/kotlin/sdk/TextContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/TextContent$Companion; public static final field TYPE Ljava/lang/String; public fun ()V @@ -2503,7 +2534,7 @@ public final class io/modelcontextprotocol/kotlin/sdk/Types_utilKt { public static synthetic fun ok$default (Lio/modelcontextprotocol/kotlin/sdk/CallToolResult$Companion;Ljava/lang/String;Lkotlinx/serialization/json/JsonObject;ILjava/lang/Object;)Lio/modelcontextprotocol/kotlin/sdk/CallToolResult; } -public final class io/modelcontextprotocol/kotlin/sdk/UnknownContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentTextOrImage { +public final class io/modelcontextprotocol/kotlin/sdk/UnknownContent : io/modelcontextprotocol/kotlin/sdk/PromptMessageContentMultimodal { public static final field Companion Lio/modelcontextprotocol/kotlin/sdk/UnknownContent$Companion; public fun (Ljava/lang/String;)V public final fun component1 ()Ljava/lang/String;