diff --git a/core/src/commonMain/kotlin/com/google/adk/kt/agents/InvocationContext.kt b/core/src/commonMain/kotlin/com/google/adk/kt/agents/InvocationContext.kt index 02007a6b..bce99019 100644 --- a/core/src/commonMain/kotlin/com/google/adk/kt/agents/InvocationContext.kt +++ b/core/src/commonMain/kotlin/com/google/adk/kt/agents/InvocationContext.kt @@ -126,6 +126,12 @@ data class InvocationContext( */ val eventsCompactionConfig: EventsCompactionConfig? = null, + /** + * Optional context cache configuration for this invocation, propagated from the [App]. When + * `null`, context caching is disabled for the invocation. + */ + val contextCacheConfig: ContextCacheConfig? = null, + // State /** The user content that started this invocation. Readonly. */ val userContent: Content? = null, diff --git a/core/src/commonMain/kotlin/com/google/adk/kt/runners/AbstractRunner.kt b/core/src/commonMain/kotlin/com/google/adk/kt/runners/AbstractRunner.kt index 979ee930..5adc4e1e 100644 --- a/core/src/commonMain/kotlin/com/google/adk/kt/runners/AbstractRunner.kt +++ b/core/src/commonMain/kotlin/com/google/adk/kt/runners/AbstractRunner.kt @@ -546,6 +546,7 @@ abstract class AbstractRunner : Runner { pluginManager = pluginManager, resumabilityConfig = resumabilityConfig, eventsCompactionConfig = app?.eventsCompactionConfig, + contextCacheConfig = null, ) .let { // Run callbacks and append user message to session @@ -602,6 +603,7 @@ abstract class AbstractRunner : Runner { pluginManager = pluginManager, resumabilityConfig = resumabilityConfig, eventsCompactionConfig = app?.eventsCompactionConfig, + contextCacheConfig = null, ) val currentContext = diff --git a/core/src/commonTest/kotlin/com/google/adk/kt/runners/AbstractRunnerTest.kt b/core/src/commonTest/kotlin/com/google/adk/kt/runners/AbstractRunnerTest.kt index 0e1b3b78..2288f21c 100644 --- a/core/src/commonTest/kotlin/com/google/adk/kt/runners/AbstractRunnerTest.kt +++ b/core/src/commonTest/kotlin/com/google/adk/kt/runners/AbstractRunnerTest.kt @@ -14,9 +14,12 @@ * limitations under the License. */ +@file:OptIn(com.google.adk.kt.annotations.ExperimentalContextCachingFeature::class) + package com.google.adk.kt.runners import com.google.adk.kt.agents.BaseAgent +import com.google.adk.kt.agents.ContextCacheConfig import com.google.adk.kt.agents.InvocationContext import com.google.adk.kt.agents.LlmAgent import com.google.adk.kt.agents.ResumabilityConfig @@ -60,8 +63,11 @@ class AbstractRunnerTest { class TestRunner(agent: BaseAgent, resumable: Boolean = true) : InMemoryRunner( - agent = agent, - resumabilityConfig = ResumabilityConfig(isResumable = resumable), + App( + appName = "InMemoryRunner", + rootAgent = agent, + resumabilityConfig = ResumabilityConfig(isResumable = resumable), + ) ) { suspend fun callFindAgentToRun(context: InvocationContext, rootAgent: BaseAgent): BaseAgent { return findAgentToRun(context, rootAgent) @@ -928,6 +934,30 @@ class AbstractRunnerTest { } } + // ----- Context cache config propagation ----- + + @Test + fun runAsync_appWithoutContextCacheConfig_invocationContextConfigIsNull() = runTest { + // Sentinel non-null so the assertion meaningfully verifies the runner left it unset. + var capturedConfig: ContextCacheConfig? = ContextCacheConfig() + val agent = + DummyAgent(name = "agent") { context -> + capturedConfig = context.contextCacheConfig + emit( + Event( + author = Role.MODEL, + invocationId = context.invocationId, + content = modelMessage("resp"), + ) + ) + } + val runner = InMemoryRunner(app = App(appName = "test_app", rootAgent = agent)) + + runner.runAsync(userId = "user", sessionId = "session", newMessage = userMessage("hi")).toList() + + assertNull(capturedConfig) + } + @Test fun runAsync_defaultSummarizerUsesRootLlmAgentModel() = runTest { // No summarizer supplied: the runner must build a default LlmEventSummarizer from the root