Session Management
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()): 3Message Structure
Message
@dataclass
class Message:
id: str # msg_{UUID}
role: str # "user" | "assistant"
parts: List[Part] # Message parts
created_at: datetimePart 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 tasksMemory 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, experiences, tools, and skills, and supports custom types for application-specific needs. See Context Types for the complete purpose and path mapping.
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 → VectorizeDedup 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/
├── tools/
└── skills/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
