From 699bf1507a8eeea149743c4076dd4cfdb5444df4 Mon Sep 17 00:00:00 2001 From: Toni Klopfenstein Date: Thu, 21 May 2026 00:18:14 +0000 Subject: [PATCH 1/4] Adding multi-memory example to the sessions memory docs --- docs/sessions/memory.md | 21 ++++--- .../kotlin/snippets/sessions/MemoryExample.kt | 57 +++++++++++++++++++ 2 files changed, 71 insertions(+), 7 deletions(-) diff --git a/docs/sessions/memory.md b/docs/sessions/memory.md index 982a3d6fe0..b6938ece2b 100644 --- a/docs/sessions/memory.md +++ b/docs/sessions/memory.md @@ -1,7 +1,7 @@ # Memory: Long-Term Knowledge with `MemoryService`
- Supported in ADKPython v0.1.0Typescript v0.2.0Go v0.1.0Java v0.1.0Kotlin v0.1.0 + Supported in ADKPython v0.1.0TypeScript v0.2.0Go v0.1.0Java v0.1.0Kotlin v0.1.0
We've seen how `Session` tracks the history (`events`) and temporary data (`state`) for a *single, ongoing conversation*. But what if an agent needs to recall information from *past* conversations? This is where the concept of **Long-Term Knowledge** and the **`MemoryService`** come into play. @@ -230,12 +230,6 @@ You can also search memory from within a custom tool by using the tool context. } ``` -=== "Go" - - ```go - --8<-- "examples/go/snippets/sessions/memory_example/memory_example.go:tool_search" - ``` - === "TypeScript" ```typescript @@ -250,6 +244,12 @@ You can also search memory from within a custom tool by using the tool context. } ``` +=== "Go" + + ```go + --8<-- "examples/go/snippets/sessions/memory_example/memory_example.go:tool_search" + ``` + === "Java" ```java @@ -508,6 +508,7 @@ For example, your agent can use the framework-configured `InMemoryMemoryService` #### Example: Using Two Memory Services === "Python" + ```python from google.adk.agents import Agent from google.adk.memory import InMemoryMemoryService @@ -549,3 +550,9 @@ For example, your agent can use the framework-configured `InMemoryMemoryService` tools=[search_all_memory], ) ``` + +=== "Kotlin" + + ```kotlin + --8<-- "examples/kotlin/snippets/sessions/MemoryExample.kt:multi_memory" + ``` diff --git a/examples/kotlin/snippets/sessions/MemoryExample.kt b/examples/kotlin/snippets/sessions/MemoryExample.kt index bebc657cd8..e32508fd05 100644 --- a/examples/kotlin/snippets/sessions/MemoryExample.kt +++ b/examples/kotlin/snippets/sessions/MemoryExample.kt @@ -158,6 +158,63 @@ fun preloadMemoryAgent(model: Gemini) { // --8<-- [end:preload_memory_agent] // --8<-- [start:auto_save_callback] + +// --8<-- [start:multi_memory] +/** + * Example of using two memory services in Kotlin. + */ +suspend fun searchAllMemory( + toolContext: ToolContext, + query: String, + docsMemory: InMemoryMemoryService, +): Map> { + // Search the conversational memory (configured in the runner) + val conversational = toolContext.invocationContext.memoryService?.searchMemory( + appName = toolContext.invocationContext.session.key.appName, + userId = toolContext.invocationContext.session.key.userId, + query = query + ) + + // Search a separate docs knowledge base + val docs = docsMemory.searchMemory( + appName = "docs", + userId = "shared", + query = query + ) + + return mapOf( + "from_conversations" to + ( + conversational?.memories?.map { + it.content.parts.joinToString(" ") { p -> p.text ?: "" } + } ?: emptyList() + ), + "from_docs" to + docs.memories.map { + it.content.parts.joinToString(" ") { p -> p.text ?: "" } + }, + ) +} + +fun multiMemoryAgent(model: Gemini) { + // docs_memory could be any MemoryService implementation + val docsMemory = InMemoryMemoryService() + + val agent = + LlmAgent( + model = model, + name = "multi_memory_agent", + instruction = + Instruction( + "Answer questions using both your conversation history and the " + + "docs knowledge base. Use the search_all_memory tool.", + ), + // In a real app, you'd wrap searchAllMemory in a @Tool annotated class + // and pass docsMemory to its constructor. + ) +} +// --8<-- [end:multi_memory] + suspend fun autoSaveSessionToMemoryCallback( context: CallbackContext, ): CallbackChoice { From 296ec96eb389c705a1be785278223e397542618a Mon Sep 17 00:00:00 2001 From: Kristopher Overholt Date: Thu, 21 May 2026 13:13:52 -0500 Subject: [PATCH 2/4] Linting with ktlint --- .../kotlin/snippets/sessions/MemoryExample.kt | 61 ++++++++++--------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/examples/kotlin/snippets/sessions/MemoryExample.kt b/examples/kotlin/snippets/sessions/MemoryExample.kt index e32508fd05..eabdf688f8 100644 --- a/examples/kotlin/snippets/sessions/MemoryExample.kt +++ b/examples/kotlin/snippets/sessions/MemoryExample.kt @@ -71,17 +71,18 @@ fun main() = val userInput1 = Content.fromText(Role.USER, "My favorite project is Project Alpha.") // Run the agent - runner1.runAsync( - userId = userId, - sessionId = sessionId1, - newMessage = userInput1, - ).collect { event -> - event.content?.parts?.forEach { part -> - if (!part.text.isNullOrBlank()) { - println("Agent Response: ${part.text}") + runner1 + .runAsync( + userId = userId, + sessionId = sessionId1, + newMessage = userInput1, + ).collect { event -> + event.content?.parts?.forEach { part -> + if (!part.text.isNullOrBlank()) { + println("Agent Response: ${part.text}") + } } } - } // Get the completed session using SessionKey val session1 = sessionService.getSession(SessionKey(appName, userId, sessionId1)) @@ -106,17 +107,18 @@ fun main() = val userInput2 = Content.fromText(Role.USER, "What is my favorite project?") // Run the second agent - runner2.runAsync( - userId = userId, - sessionId = sessionId2, - newMessage = userInput2, - ).collect { event -> - event.content?.parts?.forEach { part -> - if (!part.text.isNullOrBlank()) { - println("Agent Response: ${part.text}") + runner2 + .runAsync( + userId = userId, + sessionId = sessionId2, + newMessage = userInput2, + ).collect { event -> + event.content?.parts?.forEach { part -> + if (!part.text.isNullOrBlank()) { + println("Agent Response: ${part.text}") + } } } - } } // --8<-- [end:full_example] @@ -160,6 +162,7 @@ fun preloadMemoryAgent(model: Gemini) { // --8<-- [start:auto_save_callback] // --8<-- [start:multi_memory] + /** * Example of using two memory services in Kotlin. */ @@ -169,18 +172,20 @@ suspend fun searchAllMemory( docsMemory: InMemoryMemoryService, ): Map> { // Search the conversational memory (configured in the runner) - val conversational = toolContext.invocationContext.memoryService?.searchMemory( - appName = toolContext.invocationContext.session.key.appName, - userId = toolContext.invocationContext.session.key.userId, - query = query - ) + val conversational = + toolContext.invocationContext.memoryService?.searchMemory( + appName = toolContext.invocationContext.session.key.appName, + userId = toolContext.invocationContext.session.key.userId, + query = query, + ) // Search a separate docs knowledge base - val docs = docsMemory.searchMemory( - appName = "docs", - userId = "shared", - query = query - ) + val docs = + docsMemory.searchMemory( + appName = "docs", + userId = "shared", + query = query, + ) return mapOf( "from_conversations" to From 9f9e849f9ae3635b856bbfbb44f44ac894db96b2 Mon Sep 17 00:00:00 2001 From: Kristopher Overholt Date: Thu, 21 May 2026 13:19:14 -0500 Subject: [PATCH 3/4] Fix region marker --- examples/kotlin/snippets/sessions/MemoryExample.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/kotlin/snippets/sessions/MemoryExample.kt b/examples/kotlin/snippets/sessions/MemoryExample.kt index eabdf688f8..2e2bfd1ff9 100644 --- a/examples/kotlin/snippets/sessions/MemoryExample.kt +++ b/examples/kotlin/snippets/sessions/MemoryExample.kt @@ -159,8 +159,6 @@ fun preloadMemoryAgent(model: Gemini) { } // --8<-- [end:preload_memory_agent] -// --8<-- [start:auto_save_callback] - // --8<-- [start:multi_memory] /** @@ -220,6 +218,7 @@ fun multiMemoryAgent(model: Gemini) { } // --8<-- [end:multi_memory] +// --8<-- [start:auto_save_callback] suspend fun autoSaveSessionToMemoryCallback( context: CallbackContext, ): CallbackChoice { From a1fcbadc8ec91f86769485d8ea30295969fd7900 Mon Sep 17 00:00:00 2001 From: Kristopher Overholt Date: Thu, 21 May 2026 13:21:10 -0500 Subject: [PATCH 4/4] Add license header --- .../kotlin/snippets/sessions/MemoryExample.kt | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/examples/kotlin/snippets/sessions/MemoryExample.kt b/examples/kotlin/snippets/sessions/MemoryExample.kt index 2e2bfd1ff9..678f759e2d 100644 --- a/examples/kotlin/snippets/sessions/MemoryExample.kt +++ b/examples/kotlin/snippets/sessions/MemoryExample.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package com.google.adk.kt.examples.sessions import com.google.adk.kt.agents.CallbackContext