Skip to content

OpenViking Session Management: How AI Agents Build Long-Term Memory Automatically

Problem: AI Agents Forget Everything

When I built my first conversational AI agent, I quickly ran into a frustrating problem: every session was a blank slate. The agent would ask the same questions repeatedly, forget my preferences, and make the same mistakes over and over.

The core issues were:

  • Session isolation: No learning across conversations
  • Repeated preferences: Users must restate their preferences every time
  • Repeated mistakes: Agent errors persist without correction

OpenViking solves this with automatic memory extraction that builds long-term context from every conversation.

Purpose: Automatic Memory Learning

OpenViking’s session management provides:

  • Automatic extraction: No manual memory management required
  • Six structured categories: Organized, searchable memories
  • Self-iteration: The agent gets smarter with every use

Let me show you how it works.

Session Lifecycle: The Foundation

The session is the core unit of conversation in OpenViking. Here’s the basic lifecycle:

session_lifecycle.py
from openviking import OpenViking
from openviking.message import TextPart
client = OpenViking()
# Create session
session = client.session(session_id="chat_001")
# Interact
session.add_message("user", [TextPart("I prefer dark mode for all UI elements")])
session.add_message("assistant", [TextPart("Noted, I'll use dark theme for your projects...")])
# Commit: triggers compression + memory extraction
result = session.commit()

The commit() call is where the magic happens. It triggers:

  1. Conversation compression
  2. Archive creation with L0/L1 summaries
  3. LLM-based memory extraction
  4. Memory directory updates

Session API Overview

The session API is intentionally minimal:

MethodDescription
add_message(role, parts)Add a message to the session
used(contexts, skill)Record which contexts/skills were used
commit()Commit session: archive + memory extraction

Message Structure

Each message has a structured format:

message_structure.py
from dataclasses import dataclass
from datetime import datetime
from typing import List
@dataclass
class Message:
id: str # msg_{UUID}
role: str # "user" | "assistant"
parts: List[Part] # TextPart, ContextPart, ToolPart
created_at: datetime

The parts list can contain different types:

  • TextPart: Plain text content
  • ContextPart: Referenced context
  • ToolPart: Tool call results

The Six Memory Categories

OpenViking organizes memories into six distinct categories:

CategoryOwnerDescriptionMergeable
profileuserUser identity and attributesYes
preferencesuserUser preferences and choicesYes
entitiesuserEntities like people and projectsYes
eventsuserEvents and decisionsNo
casesagentProblem + solution pairsNo
patternsagentReusable patternsYes

This categorization serves several purposes:

  1. Searchability: Find memories by type
  2. Conflict resolution: Different merge strategies per category
  3. Ownership clarity: User vs agent memories are separate

Memory Extraction Flow

When you call commit(), OpenViking runs a sophisticated extraction pipeline:

Memory Extraction Pipeline
Messages → LLM Extract → Candidate Memories
Vector Pre-filter → Find Similar Memories
LLM Dedup Decision → Create/Merge/Skip
Write to AGFS → Vectorize

The deduplication logic is particularly clever:

LevelDecisionDescription
CandidateskipDuplicate found, do nothing
CandidatecreateNew memory, create it
CandidatenoneResolve existing instead
ItemmergeMerge into existing memory
ItemdeleteDelete conflicting memory

This prevents memory bloat while ensuring important information is preserved.

Compression Strategy

Auto-archiving happens automatically on commit():

  1. Increment the compression_index
  2. Copy messages to archive directory
  3. Generate structured summary using LLM
  4. Clear current messages list

The summary format is structured for easy retrieval:

session_summary.md
# Session Summary
**One-line overview**: [Topic]: [Intent] | [Result] | [Status]
## Analysis
Key steps list
## Primary Request and Intent
User's core goal
## Key Concepts
Key technical concepts
## Pending Tasks
Unfinished tasks

This L0 summary can be further compressed into L1 overviews for long-running sessions.

Storage Structure

OpenViking uses a virtual filesystem (AGFS) for storage:

Storage Layout
viking://session/{session_id}/
├── messages.jsonl # Current messages
├── .abstract.md # Current abstract
├── .overview.md # Current overview
├── history/
│ ├── archive_001/
│ │ ├── messages.jsonl
│ │ ├── .abstract.md
│ │ └── .overview.md
│ └── archive_NNN/
└── tools/
viking://user/memories/
├── profile.md # User profile
├── preferences/
├── entities/
└── events/
viking://agent/memories/
├── cases/
└── patterns/

This structure allows:

  • Session isolation: Each session has its own namespace
  • Memory persistence: User and agent memories persist across sessions
  • Efficient retrieval: Vector search over memory directories

Practical Example: Memory Learning in Action

Let me show you a complete example of how memories are learned and retrieved:

memory_learning_example.py
from openviking import OpenViking
from openviking.message import TextPart, ContextPart
client = OpenViking()
# First session - user mentions preference
session = client.session("user_123")
session.add_message("user", [
TextPart("I prefer using TypeScript over JavaScript for all new projects")
])
session.add_message("assistant", [
TextPart("I'll use TypeScript for your project examples going forward.")
])
session.commit() # Extracts preference memory
# Later session - preference is remembered
session2 = client.session("user_123")
results = client.find(
"coding preferences",
target_uri="viking://user/memories/"
)
# Returns: user prefers TypeScript
# The agent can now use this context
session2.add_message("user", [
TextPart("Create a new API endpoint for user authentication")
])
# Agent automatically uses TypeScript based on stored preference

The key insight is that the second session has access to the preference learned in the first session—without any manual configuration.

Recording Context and Skill Usage

OpenViking also tracks what resources were used during a session:

recording_usage.py
# Record which contexts were used
session.used(contexts=[
"viking://resources/docs/api.md",
"viking://user/memories/preferences/coding.md"
])
# Record skill usage
session.used(skill={
"uri": "viking://agent/skills/search-code",
"input": "find authentication code",
"output": "found 3 files",
"success": True
})

This usage tracking enables:

  • Context relevance scoring: Learn which contexts are most useful
  • Skill optimization: Identify successful skill patterns
  • Debugging: Understand agent decision paths

How This Compares to Other Approaches

I’ve tried several memory solutions for AI agents:

ApproachProblem
No memoryEvery session starts fresh
Manual memoryDeveloper must explicitly store and retrieve
Full historyContext window overflow, expensive
RAG onlyNo structured learning, just retrieval

OpenViking’s approach combines the best of all worlds:

  • Automatic: No manual memory management
  • Structured: Six categories with clear semantics
  • Efficient: Compression keeps context manageable
  • Intelligent: LLM-powered deduplication

When to Use OpenViking Session Management

This approach is ideal when:

  • You need agents that learn user preferences over time
  • Sessions span multiple conversations
  • You want automatic knowledge accumulation
  • Memory deduplication is important

It may be overkill for:

  • Single-session chatbots
  • Stateless API integrations
  • Simple Q&A systems

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments