fix: polish SEP-1577 sampling handling (#765)
## Summary - reject empty sampling content in SamplingMessage and CreateMessageResult constructors - clarify sampling validation docs and emit an explicit error when tool_use is not followed by tool_result - return sampled text from the conformance test_sampling tool instead of content object strings Fixes #730 ## Testing - ./gradlew -Dorg.gradle.java.installations.paths="/Users/ubl/Documents/New project/oss-contributions/.jdks/jdk-21.0.11+10/Contents/Home" :kotlin-sdk-core:jvmTest :kotlin-sdk-server:jvmTest :conformance-test:compileKotlin Co-authored-by: Pavel Gorgulov <devcrocod@gmail.com>
This commit is contained in:
parent
d65c50735b
commit
75a944fb8c
2 changed files with 56 additions and 3 deletions
|
|
@ -20,8 +20,8 @@ import io.modelcontextprotocol.kotlin.sdk.types.ToolUseContent
|
|||
* 3. If the previous message contains `tool_use` blocks, the last message's
|
||||
* `tool_result` ids MUST form exactly the same set.
|
||||
*
|
||||
* On the first violation throws [IllegalArgumentException]. No-op when there are fewer
|
||||
* than two messages or no tool_use / tool_result blocks are involved.
|
||||
* On the first violation throws [IllegalArgumentException]. No-op when no
|
||||
* tool_use / tool_result blocks are involved.
|
||||
*/
|
||||
internal fun validateSamplingMessages(messages: List<SamplingMessage>) {
|
||||
if (messages.isEmpty()) return
|
||||
|
|
@ -44,6 +44,9 @@ internal fun validateSamplingMessages(messages: List<SamplingMessage>) {
|
|||
if (hasPreviousToolUse) {
|
||||
val toolUseIds = previous.filterIsInstance<ToolUseContent>().map { it.id }.toSet()
|
||||
val toolResultIds = last.filterIsInstance<ToolResultContent>().map { it.toolUseId }.toSet()
|
||||
require(toolResultIds.isNotEmpty()) {
|
||||
"tool_use blocks from previous message must be followed by matching tool_result blocks"
|
||||
}
|
||||
require(toolUseIds == toolResultIds) {
|
||||
"ids of tool_result blocks and tool_use blocks from previous message do not match"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import io.modelcontextprotocol.kotlin.sdk.types.ToolUseContent
|
|||
import kotlinx.serialization.json.JsonObject
|
||||
import org.junit.jupiter.api.assertDoesNotThrow
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
|
||||
/**
|
||||
|
|
@ -83,4 +84,21 @@ class SamplingTest {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `validate tool_use requires explicit tool_result in last message`() {
|
||||
val error = assertFailsWith<IllegalArgumentException> {
|
||||
validateSamplingMessages(
|
||||
listOf(
|
||||
SamplingMessage(Role.Assistant, toolUse("c1")),
|
||||
SamplingMessage(Role.User, TextContent("missing result")),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
"tool_use blocks from previous message must be followed by matching tool_result blocks",
|
||||
error.message,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue