diff --git a/pom.xml b/pom.xml index afb900088..66ce647fa 100644 --- a/pom.xml +++ b/pom.xml @@ -75,7 +75,7 @@ 2.3.21 2.2.0 1.11.0 - 1.4.0 + 1.5.0 3.7.0 2.35.1 3.27.7 diff --git a/tokt/src/main/kotlin/com/google/adk/tokt/JavaAdkToKt.kt b/tokt/src/main/kotlin/com/google/adk/tokt/JavaAdkToKt.kt index 24af4a6ab..7628b46cd 100644 --- a/tokt/src/main/kotlin/com/google/adk/tokt/JavaAdkToKt.kt +++ b/tokt/src/main/kotlin/com/google/adk/tokt/JavaAdkToKt.kt @@ -141,7 +141,8 @@ object JavaAdkToKt { * Java view of a Kotlin service is unwrapped to that Kotlin service, with no `dispatcher` hop. * Resumption and rewinds work across the adapter if the Java service, like * `InMemorySessionService`, returns the fields they read unchanged: `EventActions.agentState`, - * `rewindBeforeInvocationId`, and a workflow node's output, node info, and routes. + * `rewindBeforeInvocationId`, `Event.isolationScope`, and a workflow node's output, node info, + * and routes. */ @JvmStatic @JvmOverloads diff --git a/tokt/src/main/kotlin/com/google/adk/tokt/codecs/EventCodec.kt b/tokt/src/main/kotlin/com/google/adk/tokt/codecs/EventCodec.kt index 59fc574cb..efb57146f 100644 --- a/tokt/src/main/kotlin/com/google/adk/tokt/codecs/EventCodec.kt +++ b/tokt/src/main/kotlin/com/google/adk/tokt/codecs/EventCodec.kt @@ -36,7 +36,7 @@ import kotlin.jvm.optionals.getOrNull * `errorCode`, `finishReason`), the token `usageMetadata` ([UsageMetadataCodec]), * `groundingMetadata` ([GroundingMetadataCodec]) and context `cacheMetadata` * ([CacheMetadataCodec]), a workflow node's `output` and `nodeInfo` ([WorkflowCodec]), long-running - * tool ids, and the timestamp. + * tool ids, the timestamp, and the `isolationScope`. */ internal object EventCodec { @@ -49,6 +49,7 @@ internal object EventCodec { .actions(eventActionsToJava(event.actions)) event.invocationId?.let { builder.invocationId(it) } event.branch?.let { builder.branch(it) } + event.isolationScope?.let { builder.isolationScope(it) } event.content?.let { builder.content(ContentCodec.toJava(it)) } if (event.longRunningToolIds.isNotEmpty()) builder.longRunningToolIds(event.longRunningToolIds) // Streaming/error signals are set only when meaningful, so ordinary events keep the Java @@ -101,6 +102,7 @@ internal object EventCodec { route = javaActions.route().getOrNull()?.map { WorkflowCodec.routeFromJava(it) }, ), branch = event.branch().getOrNull(), + isolationScope = event.isolationScope().getOrNull(), partial = event.partial().getOrNull() ?: false, turnComplete = event.turnComplete().getOrNull() ?: false, interrupted = event.interrupted().getOrNull() ?: false, diff --git a/tokt/src/test/kotlin/com/google/adk/tokt/KtRunnerInteropTest.kt b/tokt/src/test/kotlin/com/google/adk/tokt/KtRunnerInteropTest.kt index d47b1f9a8..a9aec4db6 100644 --- a/tokt/src/test/kotlin/com/google/adk/tokt/KtRunnerInteropTest.kt +++ b/tokt/src/test/kotlin/com/google/adk/tokt/KtRunnerInteropTest.kt @@ -4383,6 +4383,21 @@ class KtRunnerInteropTest { assertEquals(listOf(fingerprintOnly, active), stored) } + @Test + fun asKtSessionService_isolationScope_survivesTheJavaStore() = runBlocking { + // A task agent resumes from events in its own scope, so the scope must survive storage. + val sessions = JavaAdkToKt.asKtSessionService(JavaInMemorySessionService()) + val key = KtSessionKey("app", "u", "s") + val session = sessions.createSession(key) + + val unusedScoped = + sessions.appendEvent(session, KtEvent(author = "task", isolationScope = "task-1")) + val unusedUnscoped = sessions.appendEvent(session, KtEvent(author = "user")) + + val stored = assertNotNull(sessions.getSession(key)).events.map { it.isolationScope } + assertEquals(listOf("task-1", null), stored) + } + @Test fun eventCodec_workflowFields_roundTripThroughTheJavaEvent() { // Java code reads these fields too, so a Kotlin Content in the output crosses as a genai one.