Skip to content
Open
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 @@ -49,7 +49,7 @@ internal object GroundingMetadataCodec {
/** Returns the Kotlin [KtGroundingMetadata] view of the genai [metadata]. */
fun fromJava(metadata: GenaiGroundingMetadata): KtGroundingMetadata =
KtGroundingMetadata(
imageSearchQueries = metadata.imageSearchQueries().getOrNull().orEmpty(),
imageSearchQueries = metadata.imageSearchQueries().getOrNull(),
groundingChunks = metadata.groundingChunks().getOrNull()?.map { chunkFromJava(it) },
groundingSupports = metadata.groundingSupports().getOrNull()?.map { supportFromJava(it) },
webSearchQueries = metadata.webSearchQueries().getOrNull(),
Expand All @@ -62,7 +62,8 @@ internal object GroundingMetadataCodec {

/** Returns the genai [GenaiGroundingMetadata] view of the Kotlin [metadata]. */
fun toJava(metadata: KtGroundingMetadata): GenaiGroundingMetadata {
val builder = GenaiGroundingMetadata.builder().imageSearchQueries(metadata.imageSearchQueries)
val builder = GenaiGroundingMetadata.builder()
metadata.imageSearchQueries?.let { builder.imageSearchQueries(it) }
metadata.groundingChunks?.let { builder.groundingChunks(it.map { c -> chunkToJava(c) }) }
metadata.groundingSupports?.let { builder.groundingSupports(it.map { s -> supportToJava(s) }) }
metadata.webSearchQueries?.let { builder.webSearchQueries(it) }
Expand Down
50 changes: 50 additions & 0 deletions tokt/src/test/kotlin/com/google/adk/tokt/KtRunnerInteropTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import com.google.adk.kt.types.GenerationConfigRoutingConfig as KtRoutingConfig
import com.google.adk.kt.types.GenerationConfigRoutingConfigManualRoutingMode as KtManualRoutingMode
import com.google.adk.kt.types.GoogleMaps as KtGoogleMaps
import com.google.adk.kt.types.GoogleSearch as KtGoogleSearch
import com.google.adk.kt.types.GroundingMetadata as KtGroundingMetadata
import com.google.adk.kt.types.HarmBlockMethod as KtHarmBlockMethod
import com.google.adk.kt.types.HarmBlockThreshold as KtHarmBlockThreshold
import com.google.adk.kt.types.HarmCategory as KtHarmCategory
Expand Down Expand Up @@ -506,6 +507,19 @@ class KtRunnerInteropTest {
}
}

/** A native Kotlin agent emitting grounding metadata that has no image search queries. */
private class GroundedKtAgent : KtBaseAgent(name = "grounded") {
override fun runAsyncImpl(context: KtInvocationContext): Flow<KtEvent> = flow {
emit(
KtEvent(
invocationId = context.invocationId,
author = name,
groundingMetadata = KtGroundingMetadata(webSearchQueries = listOf("q")),
)
)
}
}

/** A Java plugin that requests an auth config the engine cannot represent, from before-agent. */
private class AuthConfigRequestingJavaPlugin : JavaBasePlugin("auth_config_plugin") {
override fun beforeAgentCallback(
Expand Down Expand Up @@ -4134,6 +4148,42 @@ class KtRunnerInteropTest {
assertEquals("the forecast", response.description().getOrNull(), "response description")
}

@Test
fun groundingMetadataCodec_withoutImageSearchQueries_leavesThemUnset() {
// The Kotlin list is nullable, but the genai builder's setter rejects a null argument.
val kt =
GroundingMetadataCodec.fromJava(
GenaiGroundingMetadata.builder().webSearchQueries(listOf("q")).build()
)
val java = GroundingMetadataCodec.toJava(KtGroundingMetadata(webSearchQueries = listOf("q")))

assertNull(kt.imageSearchQueries)
assertEquals(Optional.of(listOf("q")), java.webSearchQueries())
assertEquals(Optional.empty(), java.imageSearchQueries())
}

@Test
fun asJavaRunner_groundingMetadataWithoutImageSearchQueries_streamsTheEvent() {
// The same metadata through the Java runAsync API, which converts every engine event.
val javaRunner =
KotlinAdkToJava.asJavaRunner(KtInMemoryRunner(agent = GroundedKtAgent(), appName = "app"))

val events =
javaRunner
.runAsync(
"u",
"s",
GenaiContent.builder().role("user").parts(GenaiPart.fromText("hi")).build(),
JavaRunConfig.builder().autoCreateSession(true).build(),
)
.toList()
.blockingGet()

val metadata = assertNotNull(events.firstNotNullOfOrNull { it.groundingMetadata().getOrNull() })
assertEquals(Optional.of(listOf("q")), metadata.webSearchQueries())
assertEquals(Optional.empty(), metadata.imageSearchQueries())
}

@Test
fun groundingMetadataCodec_carriesMapsChunkText_roundTrip() {
// A maps grounding chunk's text (the place answer) must survive Java -> Kotlin -> Java; the
Expand Down
Loading