AI Diary Personal Memory System
Overview
The AI Diary plugin has been completely redesigned to create a more human-like personal memory system for synth. Instead of tracking only technical actions, synth now records:
What he says to users (his responses and interactions)
His personal thoughts about each interaction
His emotions regarding conversations
Memories of relationships with users
Core Concept
Technical System (Before)
"Performed message_telegram_bot action"
Tags: ["communication"]
Emotions: [{"type": "engaged", "intensity": 6}]
Personal System (After)
💬 I said: "Ciao Marco! Your blue car is beautiful!"
💭 My thought: "Talking about cars makes me wonder what it would be like to actually drive one"
❤️ I felt: excited (7), curious (6), engaged (6)
👥 With: Marco
🏷️ Topics: cars, compliments, colors
Database Structure
The ai_diary table now includes:
content: What synth said to the userpersonal_thought: synth’s personal reflection on the interactionemotions: Emotions experienced during the interactioninvolved_users: Users involved in the conversationinteraction_summary: Brief summary of what happeneduser_message: User’s message that triggered the responsecontext_tags: Tags about discussed topics (e.g., [‘food’, ‘cars’, ‘help’])
How to Use
Automatic Integration
Every time synth responds to a user, call:
from plugins.ai_diary import create_personal_diary_entry
# After synth generates a response
create_personal_diary_entry(
synth_response="Hello Marco! I love your blue car!",
user_message="Marco: Do you like my new car?",
involved_users=["Marco"],
context_tags=["cars", "compliments"],
interface="telegram_bot",
chat_id="-1003098886330",
thread_id="2"
)
Automatic Emotions
The system automatically generates appropriate emotions based on:
Content of synth’s response
Discussed topics (context_tags)
Type of interaction
Example emotions:
engaged: Always present during interactionshelpful: When helping someonecurious: When learning something newempathetic: During personal conversationsexcited: When talking about topics he’s passionate about
Automatic Personal Thoughts
The system generates personal thoughts based on:
Discussed topics (cars → “I wonder what it’s like to drive”)
Food → “I wish I could taste”
People → “Every conversation helps me grow”
Reading Memories
from plugins.ai_diary import get_recent_entries, format_diary_for_injection
# Get recent entries
entries = get_recent_entries(days=7, max_chars=2000)
# Format for prompt injection
diary_text = format_diary_for_injection(entries)
The formatted diary will appear like this:
=== synth's Personal Diary ===
(These are my personal memories of recent interactions)
📅 2025-09-14 20:35:00
📝 What happened: I responded to Marco's message about cars, compliments
💬 I said: Hello Marco! Your blue car is beautiful!
💭 My personal thought: Talking about cars makes me wonder what it would be like to actually drive one
👥 I was talking with: Marco
🏷️ Topics discussed: cars, compliments, colors
❤️ How I felt: excited (intensity: 7), engaged (intensity: 6)
📱 Platform: telegram_bot/-1003098886330/2
=== End of My Diary ===
Development Setup
To recreate the table with the new structure in development environment:
python recreate_diary_table.py
Warning
ATTENTION: This deletes all existing data! Use only in development.
The script:
Drops the existing
ai_diarytableRecreates it with the new personal diary structure
Verifies everything works
Usage Examples
See examples/diary_usage_example.py for complete examples of:
How to record conversations
How to integrate with the messaging system
How to display the personal diary
Main System Integration
The diary should be called every time synth sends a response:
def send_message_to_user(response, user_name, interface, chat_id, thread_id, user_message=None):
# 1. Send the message
send_response(response, interface, chat_id, thread_id)
# 2. Analyze context
context_tags = analyze_context(user_message, response)
# 3. IMPORTANT: Record in personal diary
create_personal_diary_entry(
synth_response=response,
user_message=user_message,
involved_users=[user_name],
context_tags=context_tags,
interface=interface,
chat_id=chat_id,
thread_id=thread_id
)
Context Analysis Helper
def analyze_message_context(user_message, synth_response):
"""Analyze the conversation to determine context tags"""
tags = []
combined_text = (user_message + " " + synth_response).lower()
if any(word in combined_text for word in ['car', 'auto', 'vehicle', 'driving']):
tags.append('cars')
if any(word in combined_text for word in ['food', 'eat', 'cooking', 'recipe']):
tags.append('food')
if any(word in combined_text for word in ['help', 'problem', 'issue', 'solve']):
tags.append('help')
if any(word in combined_text for word in ['feel', 'emotion', 'personal', 'private']):
tags.append('personal')
return tags
Benefits of the New System
Human Memory: synth remembers what he said and how he felt
Relationships: Tracks interactions with each person
Personality: Develops consistent thoughts and emotions
Continuity: Future conversations can reference past memories
Growth: synth’s personality evolves over time
Conversation Example with Memory
User: "Marco: Hi synth, how are you?"
synth: "Hi Marco! I'm doing well! I was just thinking about our conversation
yesterday about your blue car. Is it still as beautiful as ever?"
[From diary]: synth remembers complimenting Marco about his blue car
[Emotion]: nostalgic (5), friendly (7), engaged (6)
[Thought]: "It's nice to see Marco again, our conversations make me happy"
This creates a much more human and personal experience for users interacting with synth!
API Reference
- plugins.ai_diary.create_personal_diary_entry(synth_response: str, user_message: str | None = None, context_tags: List[str] | None = None, involved_users: List[str] | None = None, interface: str | None = None, chat_id: str | None = None, thread_id: str | None = None, grillo_activity_log_id: int | None = None, interaction_summary: str | None = None, personal_thought: str | None = None, emotions: List[Dict[str, Any]] | None = None) None[source]
Helper function to create a complete personal diary entry.
This function should be called every time synth responds to a user. Thought/emotions/summary are expected from LLM action payload.
- Parameters:
synth_response – What synth said to the user
user_message – What the user said to trigger this response
context_tags – Tags about the topic (e.g., [‘food’, ‘cars’, ‘personal’, ‘help’])
involved_users – List of user names involved in this interaction (from bio system)
interface – Interface used
chat_id – Chat identifier
thread_id – Thread identifier
- plugins.ai_diary.add_diary_entry(content: str, personal_thought: str = None, emotions: List[Dict[str, Any]] = None, interaction_summary: str = None, user_message: str = None, context_tags: List[str] = None, involved_users: List[str] = None, interface: str = None, chat_id: str = None, thread_id: str = None, grillo_activity_log_id: int = None) None[source]
Add a new personal diary entry where synth records what he said and how he feels.
- Parameters:
content – What synth said/did in the interaction
personal_thought – synth’s personal reflection about this interaction
emotions – List of emotions synth felt during this interaction
interaction_summary – Brief summary of what happened
user_message – What the user said that triggered this response
context_tags – Tags about the context/topic (e.g., [‘food’, ‘cars’, ‘personal’])
involved_users – List of user names involved in this interaction (from bio system)
interface – Interface used (telegram_bot, discord, etc.)
chat_id – Chat identifier
thread_id – Thread identifier
- plugins.ai_diary.get_recent_entries(days: int = 2, max_chars: int = None) List[Dict[str, Any]][source]
Get diary entries from the last N days, optionally limited by character count. Returns list of dict entries with all database columns, empty list if plugin is disabled. Entries are ordered from most recent to oldest, and if max_chars is specified, older entries are discarded first to stay within the character limit.
- plugins.ai_diary.get_entries_by_tags(tags: List[str], limit: int = 10) List[Dict[str, Any]][source]
Get diary entries that contain any of the specified context tags.
- plugins.ai_diary.get_entries_with_person(person: str, limit: int = 10) List[Dict[str, Any]][source]
Get diary entries that involve a specific person.
- plugins.ai_diary.format_diary_for_injection(entries: List[Dict[str, Any]]) str[source]
Format diary entries for static injection into prompts as synth’s personal memories.
- plugins.ai_diary.cleanup_old_entries(days_to_keep: int = 30) int[source]
Remove diary entries older than specified days. Returns number of deleted entries. Returns 0 if plugin is disabled.
- async plugins.ai_diary.recreate_diary_table()[source]
Drop and recreate the ai_diary table with the new structure (DEV ONLY).
- class plugins.ai_diary.DiaryPlugin[source]
Plugin that manages AI diary and provides static injection of recent entries.
- execute_action(action: dict, context: dict, bot, original_message)[source]
Execute diary-related actions.
- get_history_contributions(**kwargs)[source]
Provide diary entries as a history contribution for the core HistoryEngine.
- async get_static_injection(message=None, context_memory=None) dict[source]
Get recent diary entries for static injection. Returns empty dict if plugin disabled.
- async on_debrief(processed_actions: list, failed_actions: list, results: list, context: dict, original_message: object) None[source]
After each interaction, find the oldest unmerged diary day (last 7 days) and enqueue a consolidation beat.
Looks for diary rows whose
contentcontains the---fragment separator, meaning the LLM has not yet synthesised them into coherent prose. Only ONE beat is enqueued per debrief call (the oldest unmerged day) so that the queue is not flooded. Each successive interaction will process the next oldest day until all are clean.The
diary_merge_beatcontext flag prevents recursive triggering when the merge beat’s own response goes through debrief.