importorg.llm4s.agent.memory._// Create a memory managervalresult=for{manager<-SimpleMemoryManager.empty// Record user factsm1<-manager.recordUserFact(content="Prefers Scala over Java",userId=Some("user-123"),importance=Some(0.9))// Record entity knowledgem2<-m1.recordEntityFact(entityId=EntityId("anthropic"),content="AI company that created Claude",importance=Some(0.8))// Get relevant context for a querycontext<-m2.getRelevantContext("Tell me about Scala programming")}yieldcontextresultmatch{caseRight(ctx)=>println(s"Context: $ctx")caseLeft(err)=>println(s"Error: $err")}
Memory Types
Type
Purpose
Example
Conversation
Chat history
“User asked about weather”
UserFact
User preferences/info
“Prefers dark mode”
Entity
Knowledge about entities
“Paris is capital of France”
Knowledge
External knowledge
“Scala 3 released in 2021”
Task
Task outcomes
“Generated report successfully”
Custom
Application-specific
Any custom memory type
Memory Manager
The MemoryManager is the main interface for working with memory:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
importorg.llm4s.agent.memory._// Create with default in-memory storevalmanager=SimpleMemoryManager.empty// Create with configurationvalconfiguredManager=SimpleMemoryManager(config=MemoryConfig(autoRecordMessages=true,autoExtractEntities=false,defaultImportance=0.5,contextTokenBudget=2000,consolidationEnabled=true),store=newInMemoryStore())
Configuration Options
Option
Default
Description
autoRecordMessages
true
Automatically record conversation turns
autoExtractEntities
false
Extract entities from messages via LLM
defaultImportance
0.5
Default importance score (0-1)
contextTokenBudget
2000
Max tokens for context retrieval
consolidationEnabled
true
Enable memory consolidation
Recording Memory
User Facts
1
2
3
4
5
6
// Record a user preferencevalresult=manager.recordUserFact(content="Prefers functional programming",userId=Some("user-123"),importance=Some(0.9))
Entity Knowledge
1
2
3
4
5
6
// Record knowledge about an entityvalresult=manager.recordEntityFact(entityId=EntityId("scala-lang"),content="Scala is a JVM language combining OOP and FP",importance=Some(0.8))
External Knowledge
1
2
3
4
5
6
// Record external knowledgevalresult=manager.recordKnowledge(content="The latest LLM4S version is 0.5.0",source=Some("release-notes"),importance=Some(0.7))
Task Outcomes
1
2
3
4
5
6
// Record a task resultvalresult=manager.recordTask(content="Successfully generated quarterly report",taskId=Some("task-456"),importance=Some(0.6))
Conversation Messages
1
2
3
4
5
6
7
8
9
10
11
12
13
importorg.llm4s.llmconnect.model._// Record a conversation turnvalresult=manager.recordMessage(message=UserMessage("What's the weather in Paris?"),conversationId=Some(ConversationId("conv-789")))// Record entire conversationvalresult=manager.recordConversation(conversation=conversation,conversationId=ConversationId("conv-789"))
Retrieving Memory
Relevant Context
Get context relevant to a query using semantic search:
1
2
3
4
5
valcontext=manager.getRelevantContext(query="Tell me about Scala programming",maxTokens=Some(1000),memoryTypes=Some(Set(MemoryType.UserFact,MemoryType.Knowledge)))
valresult=for{providerConfig<-Llm4sConfig.provider()client<-LLMConnect.getClient(providerConfig)agent=newAgent(client)// Get memory manager with existing datamanager<-loadMemoryManager()// Get relevant context for the querycontext<-manager.getRelevantContext(userQuery)// Build enhanced system message with contextsystemMessage=s"""You are a helpful assistant.
|
|Relevant context from memory:
|$context""".stripMargin// Run agent with context-enhanced system messagestate<-agent.run(query=userQuery,tools=tools,systemMessage=Some(SystemMessage(systemMessage)))// Record the conversation_<-manager.recordConversation(state.conversation,conversationId)}yieldstate
Automatic Recording
1
2
3
4
5
6
7
valmanager=SimpleMemoryManager(config=MemoryConfig(autoRecordMessages=true// Automatically record all messages))// Messages are recorded automatically when using this manager
Semantic Search
With Embeddings
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
importorg.llm4s.agent.memory._// Setup embedding servicevalembeddingService=newEmbeddingService(embeddingClient)valstore=newVectorMemoryStore(embeddingService)valmanager=SimpleMemoryManager(store=store)// Record knowledgefor{m1<-manager.recordKnowledge("Paris is the capital of France")m2<-m1.recordKnowledge("Berlin is the capital of Germany")m3<-m2.recordKnowledge("Rome is the capital of Italy")// Semantic search finds relevant memoriesresults<-m3.store.search("European capitals",topK=2)}yieldresults
valresult=for{providerConfig<-Llm4sConfig.provider()client<-LLMConnect.getClient(providerConfig)manager=SimpleMemoryManager(config=MemoryConfig(autoExtractEntities=true),llmClient=Some(client)// Required for entity extraction)// Record message - entities extracted automaticallym1<-manager.recordMessage(UserMessage("I work at Anthropic in San Francisco"))// Entities "Anthropic" and "San Francisco" are automatically extracted}yieldm1
Manual Extraction
1
2
3
4
valentities=manager.extractEntities(content="Claude is an AI assistant created by Anthropic")// Returns: Seq(EntityId("claude"), EntityId("anthropic"))
// Using SQLite for persistencevalresult=for{// Create persistent storestore<-SQLiteMemoryStore.file("/path/to/memory.db")manager=SimpleMemoryManager(store=store)// Record memories (automatically persisted)m1<-manager.recordUserFact("User preference",Some("user-1"))// On next session, create manager with same store path// All memories are automatically loaded}yieldm1
objectPersistentMemory{privatevaldbPath="/path/to/memory.db"defgetManager():Result[SimpleMemoryManager]={for{store<-SQLiteMemoryStore.file(dbPath)}yieldSimpleMemoryManager(store=store)}}// Session 1valresult1=for{manager<-PersistentMemory.getManager()m<-manager.recordUserFact("Likes Scala",Some("user-1"))}yieldm// Session 2 (later)valresult2=for{manager<-PersistentMemory.getManager()context<-manager.getUserContext("user-1")// context includes "Likes Scala" from session 1}yieldcontext
Best Practices
1. Set Appropriate Importance
1
2
3
4
5
6
7
8
// High importance - core user preferencesmanager.recordUserFact("Primary programming language is Scala",importance=Some(0.9))// Medium importance - useful but not criticalmanager.recordKnowledge("Attended ScalaDays 2024",importance=Some(0.6))// Low importance - ephemeral informationmanager.recordTask("Ran tests at 10am",importance=Some(0.3))
2. Use Specific Memory Types
1
2
3
4
5
6
7
8
9
10
11
// Don't use generic Knowledge for everything// Use specific types for better retrieval// For user preferencesmanager.recordUserFact(...)// For entity-specific informationmanager.recordEntityFact(...)// For external knowledgemanager.recordKnowledge(...)
3. Manage Context Token Budget
1
2
3
4
5
6
7
8
9
valmanager=SimpleMemoryManager(config=MemoryConfig(contextTokenBudget=2000// Limit context size))// Context retrieval respects the budgetvalcontext=manager.getRelevantContext(query)// Returns <= 2000 tokens of context
4. Clean Up Old Memories
1
2
3
4
5
6
7
8
9
10
11
12
13
// Consolidate old memories periodicallymanager.consolidateMemories(olderThan=java.time.Duration.ofDays(30),maxToConsolidate=500)// Or delete old, low-importance memoriesstore.deleteMemories(filter=MemoryFilter(maxImportance=Some(0.3),beforeTimestamp=Some(thirtyDaysAgo)))