Back to Openviking

Session Management

docs/en/concepts/08-session.md

0.4.117.7 KB
Original Source

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.

python
session = client.session(session_id="chat_001")
session.add_message("user", [TextPart("...")])
session.commit()

Core API

MethodDescription
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

python
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

python
# 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

python
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

python
@dataclass
class Message:
    id: str              # msg_{UUID}
    role: str            # "user" | "assistant"
    parts: List[Part]    # Message parts
    created_at: datetime

Part Types

TypeDescription
TextPartText content
ImagePartImage URL content. During memory extraction, OpenViking can describe it with the configured VLM.
ContextPartContext reference (URI + abstract)
ToolPartTool call (input + output)

Compression Strategy

Archive Flow

commit() executes in two phases:

Phase 1 (synchronous, returns immediately):

  1. Increment compression_index
  2. Write messages to archive directory (messages.jsonl)
  3. Clear current messages list
  4. 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

markdown
# 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, 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 → Vectorize

Dedup Decisions

LevelDecisionDescription
CandidateskipCandidate is duplicate, skip and do nothing
CandidatecreateCreate candidate memory (optionally delete conflicting existing memories first)
CandidatenoneDo not create candidate; resolve existing memories by item decisions
Per-existing itemmergeMerge candidate content into specified existing memory
Per-existing itemdeleteDelete 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.

json
{
  "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
  }
}
FieldDescription
archive_uriArchive directory URI for this commit
extracted_atISO 8601 timestamp of extraction
operations.addsNew memories created (no before)
operations.updatesModified memories (with before and after)
operations.deletesDeleted memories (with deleted_content)
summaryCounts 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.