The Memory feature enables agents to store and retrieve information (facts) during execution, organized by concepts, subjects, and scopes. This provides short-term memory that persists across the agent’s workflow.
What is Memory?
Think of memory as a smart notebook where agents can:
Store facts : Remember important information during execution
Retrieve facts : Recall information when needed
Share knowledge : Exchange information between agents based on scope
Organize information : Structure data by concepts and subjects
Installation
import ai.koog.agents.memory.feature.AgentMemory
import ai.koog.agents.memory.providers.LocalFileMemoryProvider
import ai.koog.agents.memory.config.LocalMemoryConfig
val agent = AIAgent (
executor = myExecutor,
strategy = myStrategy
) {
install (AgentMemory) {
// Configure memory provider
memoryProvider = LocalFileMemoryProvider (
config = LocalMemoryConfig ( "my-agent-memory" ),
storage = SimpleStorage (JVMFileSystemProvider),
root = Path ( "memory/data" )
)
// Configure scope names (optional)
featureName = "code-assistant"
productName = "my-ide"
organizationName = "my-company"
}
}
Core Concepts
Facts and Concepts
Memory is organized around concepts - distinct pieces of knowledge the agent can remember:
import ai.koog.agents.memory.model.Concept
import ai.koog.agents.memory.model.FactType
import ai.koog.agents.memory.model.SingleFact
import ai.koog.agents.memory.model.MultipleFact
// Single fact - one value per concept
val themeConcept = Concept (
keyword = "ide-theme" ,
description = "User's preferred IDE theme" ,
factType = FactType.SINGLE
)
val themeFact = SingleFact (
concept = themeConcept,
value = "Dark Theme" ,
timestamp = Clock.System. now (). toEpochMilliseconds ()
)
// Multiple facts - many values per concept
val languagesConcept = Concept (
keyword = "programming-languages" ,
description = "Languages the user knows" ,
factType = FactType.MULTIPLE
)
val languagesFact = MultipleFact (
concept = languagesConcept,
values = listOf ( "Kotlin" , "Java" , "Python" ),
timestamp = Clock.System. now (). toEpochMilliseconds ()
)
Memory Subjects
Subjects categorize facts by domain:
import ai.koog.agents.memory.model.MemorySubject
import kotlinx.serialization.Serializable
// Pre-defined subject
MemorySubject.Everything // Broadest scope for general facts
// Custom subject
@Serializable
data object ProjectSubject : MemorySubject () {
override val name: String = "project"
override val promptDescription: String =
"Project details, dependencies, and configuration"
override val priorityLevel: Int = 3 // Lower = higher priority
}
Priority Levels : Lower numbers mean higher priority. If multiple subjects have facts for the same concept, the higher priority (lower number) takes precedence.
Memory Scopes
Scopes control who can access stored information:
import ai.koog.agents.memory.model.MemoryScope
// Agent scope - only this specific agent
MemoryScope. Agent ( "my-agent-123" )
// Feature scope - shared between agents of the same feature
MemoryScope. Feature ( "code-assistant" )
// Product scope - available across the entire product
MemoryScope. Product ( "my-ide" )
// Cross-product scope - shared between different products
MemoryScope.CrossProduct
Configuration Options
Option Type Default Description memoryProviderAgentMemoryProviderNoMemoryStorage provider for facts agentNameStringStrategy name Name for AGENT-scoped memory featureNameString"unknown"Name for FEATURE-scoped memory productNameString"unknown"Name for PRODUCT-scoped memory organizationNameString"unknown"Name for ORGANIZATION-scoped memory
Usage in Strategy Nodes
Loading Facts from Memory
Use pre-built nodes to load facts at the start of your agent:
import ai.koog.agents.memory.feature.nodes.nodeLoadFromMemory
val projectConcept = Concept (
"project-structure" ,
"Structure of the project including modules and folders" ,
FactType.MULTIPLE
)
val dependenciesConcept = Concept (
"project-dependencies" ,
"Dependencies in the build system" ,
FactType.MULTIPLE
)
// Load multiple concepts from memory into LLM context
val loadFromMemory by nodeLoadFromMemory (
concepts = listOf (projectConcept, dependenciesConcept)
)
Saving Facts to Memory
Save facts at the end of your agent’s execution:
import ai.koog.agents.memory.feature.nodes.nodeSaveToMemory
import ai.koog.agents.memory.config.MemoryScopeType
val saveDependencies by nodeSaveToMemory (
concept = dependenciesConcept,
subject = ProjectSubject,
scope = MemoryScopeType.ORGANIZATION // Visible across products
)
val saveProjectStructure by nodeSaveToMemory (
concept = projectConcept,
subject = ProjectSubject,
scope = MemoryScopeType.PRODUCT // Only this product
)
Auto-Detecting Facts
Let the LLM extract facts automatically from the conversation:
import ai.koog.agents.memory.feature.nodes.nodeSaveToMemoryAutoDetectFacts
val saveAutoDetect by nodeSaveToMemoryAutoDetectFacts < Unit >(
subjects = listOf (ProjectSubject, MemorySubject.Everything)
)
Manual Memory Operations
For full control, use the memory feature directly:
import ai.koog.agents.memory.feature.withMemory
val saveUserPreference by node {
withMemory {
// Save a fact manually
memoryFeature. save (
fact = SingleFact (
concept = Concept ( "favorite-color" , "User's favorite color" , FactType.SINGLE),
value = "Red" ,
timestamp = getCurrentTimestamp ()
),
subject = MemorySubject.Everything,
scope = MemoryScopeType.ORGANIZATION
)
}
}
val loadProjectInfo by node {
withMemory {
// Load facts manually using higher-level abstraction
loadFactsToAgent (
Concept ( "project-structure" , "Project structure" , FactType.MULTIPLE)
)
}
}
Memory Providers
LocalFileMemoryProvider
Stores facts in the local file system:
import ai.koog.agents.memory.providers.LocalFileMemoryProvider
import ai.koog.agents.memory.config.LocalMemoryConfig
import ai.koog.agents.memory.storage.SimpleStorage
val memoryProvider = LocalFileMemoryProvider (
config = LocalMemoryConfig ( "agent-memory" ),
storage = SimpleStorage (JVMFileSystemProvider),
root = Path ( "memory/data" )
)
Encrypted Storage
For sensitive information, use encrypted storage:
import ai.koog.agents.memory.storage.EncryptedStorage
import ai.koog.agents.memory.storage.Aes256GCMEncryption
val secureStorage = EncryptedStorage (
fs = JVMFileSystemProvider,
encryption = Aes256GCMEncryption ( "your-secret-key" )
)
val memoryProvider = LocalFileMemoryProvider (
config = LocalMemoryConfig ( "secure-memory" ),
storage = secureStorage,
root = Path ( "memory/secure" )
)
NoMemory Provider
Default provider that doesn’t store anything:
import ai.koog.agents.memory.providers.NoMemory
val memoryProvider = NoMemory // No persistence
Memory Maintenance
Clean up old or unused facts:
// Remove facts older than 30 days
memoryProvider. cleanup {
olderThan (timeProvider. getCurrentTimestamp () - 30 .days)
}
// Remove specific concepts
memoryProvider. cleanup {
withConcept ( "temporary-data" )
}
// Compact storage to save space
memoryProvider. compact ()
Complete Example
import ai.koog.agents.core.dsl.graphStrategy
import ai.koog.agents.memory.feature.AgentMemory
import ai.koog.agents.memory.feature.nodes. *
import ai.koog.agents.memory.model. *
import ai.koog.agents.memory.config.MemoryScopeType
// Define concepts
val userPreferenceConcept = Concept (
"user-preferences" ,
"User's preferences and settings" ,
FactType.MULTIPLE
)
val projectConcept = Concept (
"project-info" ,
"Current project information" ,
FactType.SINGLE
)
// Create custom subject
@Serializable
data object UserSubject : MemorySubject () {
override val name = "user"
override val promptDescription = "User preferences and settings"
override val priorityLevel = 2
}
val agent = AIAgent (
executor = openAIExecutor,
llmModel = OpenAIModels.Chat.GPT4o,
strategy = graphStrategy {
// Load facts at start
val loadMemory by nodeLoadFromMemory (
concepts = listOf (userPreferenceConcept, projectConcept)
)
val processTask by node < String , String > { input ->
// Your agent logic here
"Processed: $input "
}
// Save facts at end
val saveMemory by nodeSaveToMemory (
concept = projectConcept,
subject = UserSubject,
scope = MemoryScopeType.PRODUCT
)
edges {
start goesTo loadMemory
loadMemory goesTo processTask
processTask goesTo saveMemory
saveMemory goesTo finish
}
}
) {
install (AgentMemory) {
memoryProvider = LocalFileMemoryProvider (
config = LocalMemoryConfig ( "demo-memory" ),
storage = SimpleStorage (JVMFileSystemProvider),
root = Path ( "./memory" )
)
productName = "demo-app"
}
}
// Run the agent
val result = agent. run ( "Analyze project dependencies" )
println (result)
Best Practices
Begin with MemorySubject.Everything and MemoryScope.Agent before creating custom subjects and broader scopes.
Make concept keywords and descriptions clear and specific. The LLM uses descriptions to understand what to extract.
Choose appropriate fact types
Use SINGLE for atomic facts (“build system: Gradle”) and MULTIPLE for collections (“dependencies: […]”)
Use narrower scopes (Agent, Feature) for sensitive data and broader scopes (Product, Organization) for shared knowledge.
Implement cleanup routines to remove old facts and prevent storage bloat.
Security : Never store secrets or credentials in memory. Use encrypted storage for sensitive information and implement proper cleanup policies.
Long-term Memory Persistent memory with vector search for cross-session knowledge
History Compression Compress conversation history using memory-based fact extraction