Skip to main content

Memory Integration

Chat automatically manages conversation memory through the Memory system. It handles conversation history, summarization, and user profiles.

Memory Features

Chat integrates with Memory to provide:
  • Full Session Memory: Complete conversation history stored in InteractionSession.chat_history
  • Summary Memory: Automatic conversation summarization (requires model configuration)
  • User Analysis Memory: User profile tracking and analysis (requires model configuration)

Basic Memory Usage

import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        full_session_memory=True
    )

    # Chat automatically uses memory
    response1 = await chat.invoke("My name is Alice")
    print(response1)
    
    response2 = await chat.invoke("What's my name?")  # Agent remembers from previous message
    print(response2)


if __name__ == "__main__":
    asyncio.run(main())

Advanced Memory Configuration

import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        full_session_memory=True,
        summary_memory=True,
        user_analysis_memory=True,
        num_last_messages=50,
        feed_tool_call_results=True
    )

    await chat.invoke("Hi! My name is Alice and I love Python programming.")
    await chat.invoke("What's my name and what do I love?")
    await chat.invoke("Can you help me write a Python function to calculate fibonacci numbers?")
    await chat.invoke("Can you also help me optimize it?")

    print(f"Total cost: ${chat.total_cost:.4f} | Tokens: {chat.input_tokens + chat.output_tokens:,} | Messages: {len(chat.all_messages)}")


if __name__ == "__main__":
    asyncio.run(main())
Note: summary_memory and user_analysis_memory require the agent’s model to be configured. They use agent.model for LLM-based summarization and user trait extraction.

Memory with Custom Storage

import asyncio
from upsonic import Agent, Chat
from upsonic.storage.providers import SqliteStorage


async def main():
    # Setup persistent storage
    storage = SqliteStorage(
        db_file="chat.db",
        sessions_table_name="sessions",
        profiles_table_name="profiles"
    )
    
    # Create agent
    agent = Agent("openai/gpt-4o")

    # First session - store information
    chat1 = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        storage=storage,
        full_session_memory=True,
        summary_memory=True,
        user_analysis_memory=True,
    )
    
    response1 = await chat1.invoke("Remember: I prefer dark mode")
    print(f"Response 1: {response1}")
    
    # Second session - retrieve information from memory
    chat2 = Chat(
        session_id="session2",
        user_id="user1",
        agent=agent,
        storage=storage,
        full_session_memory=True,
        summary_memory=True,
        user_analysis_memory=True,
    )
    
    response2 = await chat2.invoke("What's my preference?")
    print(f"Response 2: {response2}")


if __name__ == "__main__":
    asyncio.run(main())

User Profile Schema

Use a custom Pydantic model for structured user profiles:
import asyncio
from typing import Optional
from pydantic import BaseModel, Field
from upsonic import Agent, Chat


class UserProfile(BaseModel):
    name: str = Field(description="The user's name as mentioned in the conversation")
    
    # Use explicit fields instead of dict - this works!
    theme_preference: Optional[str] = Field(
        default=None,
        description="User's UI theme preference (e.g., 'dark mode', 'light mode')"
    )
    programming_language: Optional[str] = Field(
        default=None,
        description="User's preferred programming language (e.g., 'Python', 'JavaScript')"
    )


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        user_profile_schema=UserProfile,
        user_analysis_memory=True
    )

    # Send messages that will trigger user analysis
    response1 = await chat.invoke("Hi, I'm Alice and I prefer dark mode and Python programming")
    print(f"Response 1: {response1}\n")

    response2 = await chat.invoke("What do you know about my preferences?")
    print(f"Response 2: {response2}\n")

    # Retrieve and display extracted profile data
    from upsonic.storage.session.sessions import UserProfile as StorageUserProfile
    import json
    
    profile = await chat._memory.storage.read_async("user1", StorageUserProfile)
    if profile and profile.profile_data:
        print("=" * 60)
        print("Extracted Profile Data:")
        print("=" * 60)
        print(json.dumps(profile.profile_data, indent=2))
        
        # Reconstruct and display
        try:
            custom_profile = UserProfile.model_validate(profile.profile_data)
            print("\n✅ Extracted Profile:")
            print(f"  Name: {custom_profile.name}")
            print(f"  Theme Preference: {custom_profile.theme_preference}")
            print(f"  Programming Language: {custom_profile.programming_language}")
        except Exception as e:
            print(f"\n❌ Error: {e}")

    print(f"\nTotal cost: ${chat.total_cost:.4f} | Tokens: {chat.input_tokens + chat.output_tokens:,}")


if __name__ == "__main__":
    asyncio.run(main())

Dynamic Profile Schema

Enable automatic schema generation from conversations:
import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        dynamic_user_profile=True,  # Automatically generate schema fields
        user_analysis_memory=True  # Required for dynamic profiles
    )

    # The schema will be automatically generated based on user conversations
    # Fields are extracted as the user mentions information
    
    # Invoke chat
    response = await chat.invoke("Hello my name is Bob")
    print(response)


if __name__ == "__main__":
    asyncio.run(main())
When dynamic_user_profile=True, the system automatically identifies 2-5 relevant traits from conversations and creates a dynamic schema. This is useful when you don’t know the user profile structure in advance. Note: If both dynamic_user_profile=True and user_profile_schema are provided, the dynamic schema takes precedence.

Memory Modes

  • update: Incrementally update user profiles, merging new traits with existing ones (default)
  • replace: Replace user profiles completely on each update
import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        user_analysis_memory=True,
        user_memory_mode="update"  # or "replace"
    )

    # Invoke chat
    response = await chat.invoke("Explain Generative AI")
    print(response)


if __name__ == "__main__":
    asyncio.run(main())

Limiting Message History

The num_last_messages parameter limits conversation history to the last N message pairs (request-response pairs):
import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        full_session_memory=True,
        num_last_messages=20  # Keep last 20 request-response pairs
    )

    # Invoke chat
    response = await chat.invoke("What are Large Language Models?")
    print(response)


if __name__ == "__main__":
    asyncio.run(main())
This helps manage context size and reduce token costs for long conversations.

Tool Call Filtering

By default, tool calls are excluded from memory. Enable them with feed_tool_call_results:
import asyncio
from upsonic import Agent, Chat


async def main():
    agent = Agent("openai/gpt-4o")

    chat = Chat(
        session_id="session1",
        user_id="user1",
        agent=agent,
        full_session_memory=True,
        feed_tool_call_results=True  # Include tool execution results
    )

    # Invoke chat
    response = await chat.invoke("Define Supervised Learning")
    print(response)


if __name__ == "__main__":
    asyncio.run(main())
When False (default), tool-related messages are filtered from chat_history to keep memory focused on user interactions.