Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import kotlinx.serialization.json.JsonElement
* Input specification for a command.
*
* Specifies how the agent should collect input for this command.
*
* Note: Default deserializer for this sealed class is configured in [com.agentclientprotocol.rpc.ACPJson]
* to fall back to [Unstructured] when no type discriminator is present.
*/
@Serializable
@JsonClassDiscriminator(TYPE_DISCRIMINATOR)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

package com.agentclientprotocol.rpc

import com.agentclientprotocol.model.AvailableCommandInput
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KSerializer
import kotlinx.serialization.Serializable
Expand All @@ -16,6 +17,8 @@ import kotlinx.serialization.json.JsonDecoder
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.modules.SerializersModule
import kotlinx.serialization.modules.polymorphic
import kotlin.jvm.JvmInline

/**
Expand Down Expand Up @@ -170,13 +173,21 @@ public enum class JsonRpcErrorCode(public val code: Int, public val message: Str
RESOURCE_NOT_FOUND(-32002, "Resource not found")
}

private val acpSerializersModule = SerializersModule {
polymorphic(AvailableCommandInput::class) {
subclass(AvailableCommandInput.Unstructured::class, AvailableCommandInput.Unstructured.serializer())
defaultDeserializer { AvailableCommandInput.Unstructured.serializer() }
}
}

@OptIn(ExperimentalSerializationApi::class)
public val ACPJson: Json by lazy {
Json {
ignoreUnknownKeys = true
encodeDefaults = true
isLenient = true
explicitNulls = false
serializersModule = acpSerializersModule
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class EmbeddedResourceResourceTest {
class SerializationTests {

@Test
fun `decodes resource content without discriminator`() {
Expand Down Expand Up @@ -50,4 +50,53 @@ class EmbeddedResourceResourceTest {
assertEquals("application/octet-stream", resource.mimeType)
assertEquals("file:///tmp/data.bin", resource.uri)
}

@Test
fun `decodes AvailableCommandInput without discriminator defaults to Unstructured`() {
val payload = """
{
"hint": "optional custom review instructions"
}
""".trimIndent()

val input = ACPJson.decodeFromString(AvailableCommandInput.serializer(), payload)

assertTrue(input is AvailableCommandInput.Unstructured)
assertEquals("optional custom review instructions", input.hint)
}

@Test
fun `decodes AvailableCommandInput with explicit discriminator`() {
val payload = """
{
"type": "unstructured",
"hint": "enter your query"
}
""".trimIndent()

val input = ACPJson.decodeFromString(AvailableCommandInput.serializer(), payload)

assertTrue(input is AvailableCommandInput.Unstructured)
assertEquals("enter your query", input.hint)
}

@Test
fun `decodes AvailableCommand with input without discriminator`() {
val payload = """
{
"name": "review",
"description": "Review code",
"input": {
"hint": "optional custom review instructions"
}
}
""".trimIndent()

val command = ACPJson.decodeFromString(AvailableCommand.serializer(), payload)

assertEquals("review", command.name)
assertEquals("Review code", command.description)
assertTrue(command.input is AvailableCommandInput.Unstructured)
assertEquals("optional custom review instructions", command.input.hint)
}
}
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ plugins {
private val buildNumber: String? = System.getenv("GITHUB_RUN_NUMBER")
private val isReleasePublication = System.getenv("RELEASE_PUBLICATION")?.toBoolean() ?: false

private val baseVersion = "0.10.1"
private val baseVersion = "0.10.2"

allprojects {
group = "com.agentclientprotocol"
Expand Down
Loading