@@ -20,6 +20,7 @@ package com.google.adk.kt.runners
2020
2121import com.google.adk.kt.agents.BaseAgent
2222import com.google.adk.kt.agents.InvocationContext
23+ import com.google.adk.kt.agents.LlmAgent
2324import com.google.adk.kt.agents.ResumabilityConfig
2425import com.google.adk.kt.agents.RunConfig
2526import com.google.adk.kt.agents.findAgent
@@ -41,6 +42,9 @@ import com.google.adk.kt.sessions.Session
4142import com.google.adk.kt.sessions.SessionKey
4243import com.google.adk.kt.sessions.SessionService
4344import com.google.adk.kt.sessions.State
45+ import com.google.adk.kt.summarizer.EventsCompactionConfig
46+ import com.google.adk.kt.summarizer.LlmEventSummarizer
47+ import com.google.adk.kt.summarizer.SlidingWindowEventCompactor
4448import com.google.adk.kt.telemetry.trace
4549import com.google.adk.kt.types.Blob
4650import com.google.adk.kt.types.Content
@@ -53,39 +57,64 @@ import kotlinx.coroutines.flow.map
5357import kotlinx.coroutines.flow.toList
5458import kotlinx.coroutines.runBlocking
5559
56- /* *
57- * An abstract base class for [Runner] implementations that provides common orchestration logic.
58- *
59- * Subclasses may be constructed either from explicit fields or from an [App] (via the [App]-based
60- * constructor), which supplies the [App.appName] and [App.rootAgent].
61- */
62- abstract class AbstractRunner (
63- override val appName : String ,
64- override val agent : BaseAgent ,
65- override val sessionService : SessionService ,
66- override val artifactService : ArtifactService ? ,
67- override val memoryService : MemoryService ? ,
68- override val pluginManager : PluginManager ,
69- override val resumabilityConfig : ResumabilityConfig = ResumabilityConfig (),
70- ) : Runner {
71-
72- /* * Creates a runner from an [App], taking its [App.appName] and [App.rootAgent]. */
60+ /* * An abstract base class for [Runner] implementations that provides common orchestration logic. */
61+ abstract class AbstractRunner : Runner {
62+
63+ val app: App ?
64+ final override val appName: String
65+ final override val agent: BaseAgent
66+ final override val sessionService: SessionService
67+ final override val artifactService: ArtifactService ?
68+ final override val memoryService: MemoryService ?
69+ final override val pluginManager: PluginManager
70+ final override val resumabilityConfig: ResumabilityConfig
71+
72+ /* * Creates a runner from explicit fields, not using an [App]. */
73+ constructor (
74+ appName: String ,
75+ agent: BaseAgent ,
76+ sessionService: SessionService ,
77+ artifactService: ArtifactService ? ,
78+ memoryService: MemoryService ? ,
79+ pluginManager: PluginManager ,
80+ resumabilityConfig: ResumabilityConfig = ResumabilityConfig (),
81+ ) {
82+ this .appName = appName
83+ this .agent = agent
84+ this .sessionService = sessionService
85+ this .artifactService = artifactService
86+ this .memoryService = memoryService
87+ this .pluginManager = pluginManager
88+ this .resumabilityConfig = resumabilityConfig
89+ this .app = null
90+ }
91+
92+ /* *
93+ * Creates a runner from an [App]. The compaction config is resolved at construction (failing fast
94+ * if a default summarizer is required but the root agent is not an [LlmAgent]) and stored back on
95+ * the [app], so [App.eventsCompactionConfig] returns the effective config.
96+ */
7397 constructor (
7498 app: App ,
7599 sessionService: SessionService ,
76100 artifactService: ArtifactService ? ,
77101 memoryService: MemoryService ? ,
78102 pluginManager: PluginManager ,
79103 resumabilityConfig: ResumabilityConfig = ResumabilityConfig (),
80- ) : this (
81- app.appName,
82- app.rootAgent,
83- sessionService,
84- artifactService,
85- memoryService,
86- pluginManager,
87- resumabilityConfig,
88- )
104+ ) {
105+ this .appName = app.appName
106+ this .agent = app.rootAgent
107+ this .sessionService = sessionService
108+ this .artifactService = artifactService
109+ this .memoryService = memoryService
110+ this .pluginManager = pluginManager
111+ this .resumabilityConfig = resumabilityConfig
112+ this .app =
113+ app.copy(
114+ eventsCompactionConfig =
115+ resolveEventsCompactionConfig(app.rootAgent, app.eventsCompactionConfig)
116+ )
117+ }
89118
90119 /* *
91120 * Main entry method to run the agent in this runner.
@@ -125,6 +154,10 @@ abstract class AbstractRunner(
125154
126155 // 4. Run agent with plugins
127156 emitAll(runAgentWithPlugins(context))
157+
158+ // 5. Post-invocation context compaction. Runs once the agent has finished emitting and all
159+ // its events have been appended to `session`.
160+ runPostInvocationCompaction(session)
128161 }
129162 .trace(" invocation" )
130163
@@ -680,7 +713,38 @@ abstract class AbstractRunner(
680713 return " e-" + Uuid .random()
681714 }
682715
716+ /* *
717+ * Runs post-invocation sliding-window context compaction over [session] when configured. A no-op
718+ * when no compaction config was supplied or sliding-window compaction is not configured. The
719+ * compactor appends a single summary [Event] to [session] (via [sessionService]) when the
720+ * configured invocation interval is reached.
721+ */
722+ private suspend fun runPostInvocationCompaction (session : Session ) {
723+ val config = app?.eventsCompactionConfig ? : return
724+ if (! config.hasSlidingWindowConfig()) return
725+ SlidingWindowEventCompactor (config).compact(session, sessionService)
726+ }
727+
683728 private companion object {
684729 private val logger = LoggerFactory .getLogger(AbstractRunner ::class )
730+
731+ /* *
732+ * Returns [config] with a default [LlmEventSummarizer] injected when compaction is configured
733+ * but no summarizer was supplied. The default summarizer uses [rootAgent]'s model, so
734+ * [rootAgent] must be an [LlmAgent] in that case; otherwise an [IllegalArgumentException] is
735+ * thrown. Returns [config] unchanged when it is `null` or already carries a summarizer. Any
736+ * configured compaction strategy needs a summarizer, so this does not depend on which strategy
737+ * is set.
738+ */
739+ private fun resolveEventsCompactionConfig (
740+ rootAgent : BaseAgent ,
741+ config : EventsCompactionConfig ? ,
742+ ): EventsCompactionConfig ? {
743+ if (config == null || config.summarizer != null ) return config
744+ val model =
745+ (rootAgent as ? LlmAgent )?.model
746+ ? : throw IllegalArgumentException (" No BaseLlm model available for event compaction" )
747+ return config.copy(summarizer = LlmEventSummarizer (model))
748+ }
685749 }
686750}
0 commit comments