Session Management
August 13, 2026 · View on GitHub
Session manages conversation messages, tracks context usage, and extracts long-term memories.
Overview
Lifecycle: Create → Interact → Commit
Getting a session by ID does not auto-create it by default. Use client.get_session(..., auto_create=True) when you want missing sessions to be created automatically.
session = client.session(session_id="chat_001")
session.add_message("user", [TextPart("...")])
session.commit()
Core API
| Method | Description |
|---|---|
add_message(role, parts) | Add message |
used(contexts, skill) | Record used contexts/skills |
commit() | Commit: archive (sync) + summary generation and memory extraction (async background) |
get_task(task_id) | Query background task status |
add_message
session.add_message(
"user",
[TextPart("How to configure embedding?")]
)
session.add_message(
"assistant",
[
TextPart("Here's how..."),
ContextPart(uri="viking://user/memories/profile.md"),
]
)
session.add_message(
"user",
[
TextPart("Remember this studio layout."),
ImagePart(url="https://example.com/studio.png", detail="auto"),
]
)
used
# Record used contexts
session.used(contexts=["viking://user/memories/profile.md"])
# Record used skill
session.used(skill={
"uri": "viking://user/skills/code-search",
"input": "search config",
"output": "found 3 files",
"success": True
})
commit
result = session.commit()
# {
# "status": "accepted",
# "task_id": "uuid-xxx",
# "archive_uri": "viking://user/{user_id}/sessions/.../history/archive_001",
# "archived": True
# }
# Poll background task progress
task = client.get_task(result["task_id"])
# task["status"]: "pending" | "running" | "completed" | "failed"
# sum(task["result"]["memories_extracted"].values()): 3
Message Structure
Message
@dataclass
class Message:
id: str # msg_{UUID}
role: str # "user" | "assistant"
parts: List[Part] # Message parts
created_at: datetime
Part Types
| Type | Description |
|---|---|
TextPart | Text content |
ImagePart | Image URL content. During memory extraction, OpenViking can describe it with the configured VLM. |
ContextPart | Context reference (URI + abstract) |
ToolPart | Tool call (input + output) |
Compression Strategy
Archive Flow
commit() executes in two phases:
Phase 1 (synchronous, returns immediately):
- Increment compression_index
- Write messages to archive directory (
messages.jsonl) - Clear current messages list
- Return
task_id
Phase 2 (asynchronous background):
5. Generate structured summary (LLM) → write .abstract.md and .overview.md
6. Extract long-term memories
7. Write memory_diff.json (memory change audit log) to archive directory
8. Update active_count
9. Write .done completion marker
Summary Format
# 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
Memory Extraction
Memory Types
After a session is committed, OpenViking uses the conversation and active memory policy to extract information that can improve future interactions. It stores the result in the current user's memory space. When a conversation involves a stable Peer, relevant memories can also be stored in that Peer's space.
OpenViking includes memory types such as profile, preferences, entities, events, identity, soul, cases, trajectories, and experiences, and supports custom types for application-specific needs. See Context Types for the complete purpose and path mapping.
Within memory_policy.memory_types, experiences enables the complete Agent Evolution pipeline and automatically activates cases and trajectories. If experiences is absent, explicitly supplied cases and trajectories entries are ignored without an error.
Extraction Flow
Messages → LLM Extract → Candidate Memories
↓
Vector Pre-filter → Find Similar Memories
↓
LLM Dedup Decision → candidate(skip/create/none) + item(merge/delete)
↓
Write to AGFS → Vectorize
Dedup Decisions
| Level | Decision | Description |
|---|---|---|
| Candidate | skip | Candidate is duplicate, skip and do nothing |
| Candidate | create | Create candidate memory (optionally delete conflicting existing memories first) |
| Candidate | none | Do not create candidate; resolve existing memories by item decisions |
| Per-existing item | merge | Merge candidate content into specified existing memory |
| Per-existing item | delete | Delete specified conflicting existing memory |
Memory Diff
Each session.commit() writes a memory_diff.json to the archive directory, recording all memory changes from that commit for auditing and rollback.
{
"archive_uri": "viking://user/{user_id}/sessions/{session_id}/history/archive_001",
"extracted_at": "2026-04-21T10:00:00Z",
"operations": {
"adds": [
{
"uri": "memory/user/xxx/identity.md",
"memory_type": "identity",
"after": "Newly created file content"
}
],
"updates": [
{
"uri": "memory/user/xxx/context/project.md",
"memory_type": "context",
"before": "Content before modification",
"after": "Content after modification"
}
],
"deletes": [
{
"uri": "memory/user/xxx/context/old.md",
"memory_type": "context",
"deleted_content": "Deleted file content"
}
]
},
"summary": {
"total_adds": 1,
"total_updates": 1,
"total_deletes": 1
}
}
| Field | Description |
|---|---|
archive_uri | Archive directory URI for this commit |
extracted_at | ISO 8601 timestamp of extraction |
operations.adds | New memories created (no before) |
operations.updates | Modified memories (with before and after) |
operations.deletes | Deleted memories (with deleted_content) |
summary | Counts per operation type |
An empty memory_diff.json (all counts zero) is written even when no memory operations occurred.
Storage Structure
viking://user/{user_id}/sessions/{session_id}/
├── messages.jsonl # Current messages
├── .abstract.md # Current abstract
├── .overview.md # Current overview
├── history/
│ ├── archive_001/
│ │ ├── messages.jsonl # Written in Phase 1
│ │ ├── .abstract.md # Written in Phase 2 (background)
│ │ ├── .overview.md # Written in Phase 2 (background)
│ │ ├── memory_diff.json # Written in Phase 2 (background, memory change audit)
│ │ └── .done # Phase 2 completion marker
│ └── archive_NNN/
└── tools/
└── {tool_id}/tool.json
viking://user/memories/
├── profile.md
├── identity.md
├── soul.md
├── preferences/
├── entities/
├── events/
├── cases/
├── trajectories/
└── experiences/
viking://user/sessions/{session_id} is accepted as a short form relative to
the current request user and is canonicalized to
viking://user/{user_id}/sessions/{session_id}. The old
viking://session/{session_id} form is accepted as a backward-compatible alias
for the same current-user session path and is not a separate storage root.
Related Documents
- Architecture Overview - System architecture
- Context Types - Three context types
- Context Extraction - Extraction flow
- Context Layers - L0/L1/L2 model