C3 AI Documentation Home

Agent Long-Term Memory

Agents can learn from conversations and remember useful information for future interactions. Unlike chat memory, which is scoped to a specific conversation's message window and is lost when that chat is deleted, long-term memory is stored independently of any conversation. It persists even after a chat is deleted and is available across all future interactions. When a user asks something the agent has learned before, it retrieves that information automatically.

How it works

The memory system operates in two phases during agent execution:

  1. Recall: When a user submits a query, the agent searches for relevant memories and injects them into the system prompt before processing.

  2. Memorization: After responding, the agent analyzes the conversation to determine if anything should be saved for future use.

Both phases run automatically when you enable memory callbacks in the agent configuration.

Memory types

Memories fall into two categories:

  • User-specific memories: Personal to the user who created them. The agent uses these only when that user asks questions.
  • Global memories: Available to all users. Useful for organizational knowledge that applies broadly. This is set by the boolean field global on memory records and is configurable in the memory creation prompt and schema Genai.Memory.LongTermMemory.Config.

Enable memory for your agent

Memory runs through callbacks attached to the agent pipeline. You configure these in your agent's JSON config file.

Add the callback specification to your agent config:

JSON
{
  "name": "MyAgent_default",
  "onStepCallbacksSpec": {
    "onCallStepStart": [
      {
        "type": "Genai.Agent.Dynamic.Callback",
        "id": "agent_memory_recall",
        "callback": {
          "type": "ActionRef",
          "typeName": "Genai.Agent.Dynamic.Callback.Memory",
          "actionName": "recall"
        }
      }
    ],
    "onCallStepEnd": [
      {
        "type": "Genai.Agent.Dynamic.Callback",
        "id": "agent_memory_launchAsyncMemorization",
        "callback": {
          "type": "ActionRef",
          "typeName": "Genai.Agent.Dynamic.Callback.Memory",
          "actionName": "launchAsyncMemorization"
        }
      },
      {
        "type": "Genai.Agent.Dynamic.Callback",
        "id": "agent_memory_cleanup",
        "callback": {
          "type": "ActionRef",
          "typeName": "Genai.Agent.Dynamic.Callback.Memory",
          "actionName": "cleanup"
        }
      }
    ]
  }
}

Before step execution begins, the recall callback runs in onCallStepStart. After the step finishes, launchAsyncMemorization and cleanup both run in onCallStepEnd. The recall callback retrieves relevant memories and adds them to the system prompt (it adds the MEMORY_RECALL parameter). The launchAsyncMemorization callback analyzes the conversation and creates new memories if needed. The cleanup callback clears any temporary parameters (MEMORY_RECALL) used for memory recall.

Configure memory settings

Memory behavior is controlled through Genai.Memory.LongTermMemory.Config. The default configuration includes:

SettingDefaultDescription
memoryRecallCount5Number of memories retrieved per query
memoryResolutionCount10Maximum memories to compare during conflict resolution
dynamicAgentNameDynamicAgent_defaultAgent used for memory processing

You can customize these by creating a new config record or updating the default.

Prompt requirements

For memory recall to work, your agent's system prompt or force-solution prompt must include a {{MEMORY_RECALL}} placeholder parameter. The callback replaces this placeholder with relevant memories formatted as context.

Example system prompt snippet:

Text
You are a helpful assistant.

## Previous Knowledge
 {{MEMORY_RECALL}}

## Instructions
...

If neither the system prompt nor the force-solution prompt defines this parameter, the recall callback throws an error.

Memory resolution

When the agent creates a new memory similar to an existing one, it runs a resolution process. The agent determines one of three actions:

  • KEEP: The memories are unrelated, so both remain.
  • UPDATE: The memories overlap but have complementary information. The agent merges them.
  • DELETE: The new memory contradicts the old one. The agent removes the outdated memory.

For example, if a user previously said "Call me Dr. Smith" but later says "Actually, call me Alex." the agent deletes the old memory because they directly conflict.

Resolution runs asynchronously after memory creation.

UI feedback

When memory creation begins, a placeholder resource appears in the UI showing "Creating Memory..." status. After completion, the UI updates to show the created memories.

This polling mechanism uses the Genai.Agent.Resource.MemoryCreation type with a status field that transitions from creating to completed.

Memory storage

Memories are stored in Genai.Memory.LongTermMemory.Pg and accessed via a GenaiCore.Agent.MemoryStore.Pg configured on Genai.Memory.LongTermMemory.Config. The store:

  • Generates embeddings for similarity search
  • Filters by user ID for user-specific memories
  • Supports metadata tagging for categorization

The default memory store is available from the long-term memory config:

Python
config = c3.Genai.Memory.LongTermMemory.Config.inst()
memory_store = config.memoryStore

Create memories programmatically

You can create memories directly using the memory store from Genai.Memory.LongTermMemory.Config. This ensures the memory is embedded and stored in the same Genai.Memory.LongTermMemory.Pg collection that the recall callback queries.

Python
user_id = User.myUser().id

memory_store = Genai.Memory.LongTermMemory.Config.inst().memoryStore

passage = "What is my preferred date format?"
metadata = [{
    "content": "ISO 8601 (YYYY-MM-DD)",
    "contentToEmbed": passage,
    "description": "User prefers ISO date format",
    "global": false,
    "user": {"id": user_id},
    "details": {"query": passage, "specialization": "formatting"},
}]
memory_store.addMemories([passage], metadata=metadata)

# Trigger resolution to handle any conflicts with existing memories
Genai.Memory.LongTermMemory.Resolver.launchAsyncResolution(memory_store.id)

Retrieve memories

To query existing memories for a user:

Python
user_id = User.myUser().id

# Get memory store from long-term memory config
memory_store = Genai.Memory.LongTermMemory.Config.inst().memoryStore

# Get all memories for the current user
memories = Genai.Memory.LongTermMemory.Pg.fetch({
    "filter": Filter.eq("user.id", user_id).and(Filter.eq("memoryStoreId", memory_store.id)),
    "include": "this, details, content, description",
    "order": "descending(meta.updated)"
}).objs

# Search by similarity
spec = GenaiCore.SimilaritySearchSpec.make({
    "k": 5,
    "metadataFilter": Filter.eq("user.id", user_id)
})
results = memory_store.similaritySearch("date formatting preferences", spec)

Delete memories

Remove a specific memory by ID:

Python
Genai.Memory.LongTermMemory.Pg.forId(memory_id).remove()

Or remove all memories for a user:

Python
memory_store = Genai.Memory.LongTermMemory.Config.inst().memoryStore

Genai.Memory.LongTermMemory.Pg.removeAll(
  {
    "filter": Filter.eq("user.id", user_id).and_().eq("memoryStoreId", memory_store.id)
  },
  confirm=True
)

Troubleshooting

Memories not being recalled

  • Verify the system prompt includes {MEMORY_RECALL} parameter.
  • Check that a memory store is configured in Genai.Memory.LongTermMemory.Config.
  • Confirm the recall callback is listed in onCallStepStart.

Memories not being created

  • Review agent logs for the G.A.D.Callback.Memory prefix.
  • Verify the memorization callback is listed in onCallStepEnd.
  • Check that the LLM decides the conversation contains memorable information. Not every conversation results in a memory.

Duplicate memories appearing

  • Memory resolution runs asynchronously. Wait a few seconds and query again.
  • Check resolved field on memory records; unresolved memories are pending.

To learn more about agent memories, check the python notebook GenAI Platform Tutorials - Agent Memory.

See also

Was this page helpful?