docs/en/concepts/08-session.md
Session manages conversation messages, tracks context usage, and extracts long-term memories.
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()
| 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 |
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"),
]
)
# 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
})
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
@dataclass
class Message:
id: str # msg_{UUID}
role: str # "user" | "assistant"
parts: List[Part] # Message parts
created_at: datetime
| 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) |
commit() executes in two phases:
Phase 1 (synchronous, returns immediately):
messages.jsonl)task_idPhase 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
# 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
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.
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
| 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 |
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.
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.