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; diff --git a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt index c69d2d27..e8606a84 100644 --- a/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt +++ b/src/commonMain/kotlin/io/modelcontextprotocol/kotlin/sdk/types.kt @@ -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 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() } } 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