Sessions

August 13, 2026 ยท View on GitHub

Sessions manage conversation state, track context usage, and extract long-term memories. Sessions use tiered storage (L0/L1/L2) to optimize token usage:

  • L0 (abstract): Session overview summary
  • L1 (overview): Key decisions
  • L2 (messages): Complete messages

Sessions are stored under the current user's namespace:

viking://user/{user_id}/sessions/{session_id}

Session APIs are scoped to the authenticated user and return canonical user session URIs. URI-based APIs may also accept the backward-compatible viking://session/{session_id} alias, resolved in the same user context.

API Reference

create_session()

1. API Implementation Introduction

Create a new session. Sessions are containers for conversations, storing messages, tracking context usage, and supporting commits for long-term memory extraction.

Processing Flow:

  1. Generate or use provided session_id
  2. Initialize session metadata (creation time, user info, etc.)
  3. Create session directory structure in storage
  4. Return session info

Code Entries:

  • openviking/session/session.py:Session.__init__() - Core Session class
  • openviking/session/auto_commit_policy.py:AutoCommitPolicy - Auto-commit policy defaults and validation
  • openviking/server/routers/sessions.py:create_session() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.create_session() - Python SDK
  • crates/ov_cli/src/commands/session.rs:new_session() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrNoNoneSession ID. Creates new session with auto-generated ID if None
memory_policyobjectNoNoneDefault memory extraction policy for the session. Optional self and peer switches control write targets, optional working_memory.enabled=false skips archive summaries, and optional top-level memory_types limits extraction to specific enabled memory schemas. Including experiences automatically activates cases and trajectories; without experiences, explicitly supplied cases and trajectories are ignored. Use JSON booleans for every enabled value. Legacy boolean-like values remain accepted temporarily (including string "false", which is parsed as false) but emit a deprecation warning. When memory_types is omitted or null, all enabled memory schemas are allowed. Invalid shapes or unknown memory types are rejected with InvalidArgumentError.
auto_commit_policyobjectNoNoneOptional auto-commit policy (see table below). Any provided fields are validated, clamped to their bounds, and merged over the defaults; the effective policy is returned in the response result.auto_commit_policy and persisted into session metadata. If no policy is provided, auto commit is disabled unless memory.session_auto_commit.default_enabled=true. The policy can later be partially updated or disabled through update_session_config().

auto_commit_policy fields (all optional; omitted fields fall back to the defaults when a policy is present):

FieldTypeDefaultMaxDescription
pending_token_thresholdint1000050000When uncommitted pending tokens exceed this value (strictly greater-than), an auto commit is triggered after a message write.
message_count_thresholdint50500When the uncommitted live message count exceeds this value (strictly greater-than), an auto commit is triggered after a message write.
idle_timeout_secondsint86400604800After this many idle seconds, a session with uncommitted content becomes eligible for the server-side idle scheduler. An idle-timeout commit archives the full backlog and ignores keep_recent_count.
keep_recent_countint2500Number of recent live messages to keep (not archived) on a threshold-triggered auto commit. Idle-timeout commits ignore this and commit everything.
min_commit_interval_secondsint0604800Minimum seconds between two automatic commits (throttle).

All fields have a minimum of 0 and are clamped into [0, max]. Unknown keys are rejected with InvalidArgumentError.

3. Usage Examples

HTTP API

POST /api/v1/sessions
# Create new session (auto-generated ID)
curl -X POST http://localhost:1933/api/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key"

# Create new session with specified ID
curl -X POST http://localhost:1933/api/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"session_id": "my-custom-session-id"}'

# Create new session with a custom auto-commit policy
curl -X POST http://localhost:1933/api/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "auto_commit_policy": {
      "pending_token_threshold": 8000,
      "message_count_threshold": 40,
      "idle_timeout_seconds": 600,
      "keep_recent_count": 10,
      "min_commit_interval_seconds": 0
    }
  }'

Python SDK

import openviking as ov

# Use HTTP client
client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Create new session (auto-generated ID)
result = await client.create_session()
print(f"Session ID: {result['session_id']}")

# Create new session with specified ID
result = await client.create_session(session_id="my-custom-session-id")
print(f"Session ID: {result['session_id']}")

# Create new session with a custom auto-commit policy
result = await client.create_session(
    auto_commit_policy={
        "pending_token_threshold": 8000,
        "message_count_threshold": 40,
        "idle_timeout_seconds": 600,
        "keep_recent_count": 10,
        "min_commit_interval_seconds": 0,
    }
)
print(result["auto_commit_policy"])

TypeScript SDK

const session = await client.createSession();
console.log(session);

Go SDK

session, err := client.CreateSession(ctx, &openviking.CreateSessionOptions{
    SessionID: "my-custom-session-id",
})
if err != nil {
    return err
}
fmt.Println(session["session_id"])

CLI

ov session new

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "uri": "viking://user/alice/sessions/a1b2c3d4",
    "user": {
      "account_id": "default",
      "user_id": "alice"
    },
    "auto_commit_policy": null
  },
  "time": 0.1
}

list_sessions()

1. API Implementation Introduction

List all sessions for the current user. Returns session IDs and URI info for further operations.

Code Entries:

  • openviking/server/routers/sessions.py:list_sessions() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.list_sessions() - Python SDK
  • crates/ov_cli/src/commands/session.rs:list_sessions() - CLI command

2. Interface and Parameter Description

Parameters

None.

3. Usage Examples

HTTP API

GET /api/v1/sessions
curl -X GET http://localhost:1933/api/v1/sessions \
  -H "X-API-Key: your-key"

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

sessions = await client.list_sessions()
for s in sessions:
    print(f"{s['session_id']} -> {s['uri']}")

TypeScript SDK

console.log(await client.listSessions());

Go SDK

sessions, err := client.ListSessions(ctx)
if err != nil {
    return err
}
for _, session := range sessions {
    fmt.Println(session)
}

CLI

ov session list

Response Example

{
  "status": "ok",
  "result": [
    {
      "session_id": "a1b2c3d4",
      "uri": "viking://user/alice/sessions/a1b2c3d4",
      "is_dir": true
    },
    {
      "session_id": "e5f6g7h8",
      "uri": "viking://user/alice/sessions/e5f6g7h8",
      "is_dir": true
    }
  ],
  "time": 0.1
}

get_session()

1. API Implementation Introduction

Get session details including metadata, message statistics, commit history, etc. Supports auto-creating sessions when they don't exist.

Return Fields Description:

  • message_count: Number of current live, unarchived messages
  • total_message_count: Cumulative count of archived and current live messages (older sessions may omit this field)
  • commit_count: Number of successful commits
  • memories_extracted: Count statistics of extracted memories by category
  • last_commit_at: Time of last commit
  • auto_commit_policy: Effective auto-commit policy with defaults filled in; null when not enabled

Code Entries:

  • openviking/session/session.py:Session.load() - Session loading
  • openviking/server/routers/sessions.py:get_session() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.get_session() - Python SDK
  • crates/ov_cli/src/commands/session.rs:get_session() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID
auto_createboolNoFalseWhether to auto-create the session if it does not exist

3. Usage Examples

HTTP API

GET /api/v1/sessions/{session_id}?auto_create=false
curl -X GET http://localhost:1933/api/v1/sessions/a1b2c3d4 \
  -H "X-API-Key: your-key"

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Get existing session (raises NotFoundError if not found)
info = await client.get_session("a1b2c3d4")
print(f"Live Messages: {info['message_count']}")
print(f"Total Messages: {info.get('total_message_count', 'n/a')}")
print(f"Commits: {info['commit_count']}")

# Get or create session
info = await client.get_session("a1b2c3d4", auto_create=True)

TypeScript SDK

console.log(await client.getSession("session-id"));

Go SDK

// Get an existing session.
info, err := client.GetSession(ctx, "a1b2c3d4", nil)
if err != nil {
    return err
}
fmt.Println(info["message_count"])

// Get or create session.
info, err = client.GetSession(ctx, "a1b2c3d4", &openviking.GetSessionOptions{
    AutoCreate: true,
})
if err != nil {
    return err
}
fmt.Println(info["session_id"])

CLI

ov session get a1b2c3d4

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "created_at": "2026-03-23T10:00:00+08:00",
    "updated_at": "2026-03-23T11:30:00+08:00",
    "message_count": 5,
    "total_message_count": 20,
    "commit_count": 3,
    "memories_extracted": {
      "profile": 1,
      "preferences": 2,
      "entities": 3,
      "events": 1,
      "identity": 1,
      "soul": 1,
      "cases": 2,
      "trajectories": 1,
      "experiences": 2,
      "tools": 0,
      "skills": 0,
      "total": 14
    },
    "last_commit_at": "2026-03-23T11:00:00+08:00",
    "llm_token_usage": {
      "prompt_tokens": 5200,
      "completion_tokens": 1800,
      "total_tokens": 7000,
      "cached_tokens": 1200,
      "reasoning_tokens": 800
    },
    "user": {
      "account_id": "default",
      "user_id": "alice"
    },
    "pending_tokens": 450,
    "auto_commit_policy": {
      "pending_token_threshold": 10000,
      "message_count_threshold": 50,
      "idle_timeout_seconds": 86400,
      "keep_recent_count": 2,
      "min_commit_interval_seconds": 0
    }
  }
}

update_session_config()

1. API Implementation Introduction

Partially update the mutable configuration of an existing session. Changes take effect on subsequent message writes, idle scans, and commits. Only the /api/v1/sessions/{session_id}/config subpath accepts PATCH; the base /api/v1/sessions/{session_id} endpoint does not.

Code Entry Points:

  • openviking/server/routers/sessions.py:update_session_config() - HTTP route
  • openviking/service/session_service.py:SessionService.update_config() - Config validation and update
  • sdk/python/openviking_sdk/client.py:update_session_config() - Python SDK
  • sdk/typescript/src/client.ts:updateSessionConfig() - TypeScript SDK
  • sdk/go/sessions.go:UpdateSessionConfig() - Go SDK
  • crates/ov_cli/src/commands/session.rs:set_session_config() - CLI command

2. Interface and Parameter Description

ParameterTypeRequiredDefaultDescription
session_idstringYes-Session ID in the URL path
memory_extraction_configobjectNoOmittedMutable extraction settings. Currently supports events.tags, an array of strict key=value strings. Omit it to preserve the current tags; pass events.tags=[] to clear them. Tags are trimmed, lowercased, and deduplicated.
auto_commit_policyobject or nullNoOmittedAn object merges only the supplied policy fields into the current policy, with the same validation, clamping, defaults, and bounds documented under create_session(). Pass null to disable automatic commits; omit the field to leave the policy unchanged. Individual policy fields cannot be null.
telemetryboolean or objectNofalseSet to true, or pass {"summary": true}, to include the operation telemetry summary in the response. false omits it.

An empty request object is a valid no-op and returns the effective configuration. Unknown request fields are rejected. The response always returns the effective policy with defaults filled in, or null when automatic commits are disabled.

3. Usage Examples

HTTP API

PATCH /api/v1/sessions/{session_id}/config
# Merge one policy field and replace the default event-memory tags
curl -X PATCH http://localhost:1933/api/v1/sessions/a1b2c3d4/config \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "memory_extraction_config": {
      "events": {"tags": ["team=search", "channel=app"]}
    },
    "auto_commit_policy": {"message_count_threshold": 25},
    "telemetry": true
  }'

# Disable automatic commits without changing event-memory tags
curl -X PATCH http://localhost:1933/api/v1/sessions/a1b2c3d4/config \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"auto_commit_policy": null}'

Python SDK

result = client.update_session_config(
    "a1b2c3d4",
    memory_extraction_config={
        "events": {"tags": ["team=search", "channel=app"]}
    },
    auto_commit_policy={"message_count_threshold": 25},
)

TypeScript SDK

const result = await client.updateSessionConfig("a1b2c3d4", {
  memoryExtractionConfig: {
    events: { tags: ["team=search", "channel=app"] },
  },
  autoCommitPolicy: { message_count_threshold: 25 },
});

Go SDK

policy := map[string]any{"message_count_threshold": 25}
result, err := client.UpdateSessionConfig(ctx, "a1b2c3d4", &openviking.UpdateSessionConfigOptions{
    MemoryExtractionConfig: map[string]any{
        "events": map[string]any{"tags": []string{"team=search", "channel=app"}},
    },
    AutoCommitPolicy: &policy,
})

CLI

ov session config set a1b2c3d4 \
  --event-tags team=search,channel=app \
  --auto-commit-policy-json '{"message_count_threshold":25}'

# Clear the default tags, or disable automatic commits
ov session config set a1b2c3d4 --no-event-tags
ov session config set a1b2c3d4 --no-auto-commit

Response example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "auto_commit_policy": {
      "pending_token_threshold": 10000,
      "message_count_threshold": 25,
      "idle_timeout_seconds": 86400,
      "keep_recent_count": 2,
      "min_commit_interval_seconds": 0
    },
    "memory_extraction_config": {
      "events": {
        "tags": ["team=search", "channel=app"]
      }
    }
  },
  "telemetry": {
    "id": "tm_xxx",
    "summary": {
      "operation": "session.update_config",
      "status": "ok",
      "duration_ms": 4.2
    }
  }
}

list_tool_results()

List large tool results externalized from a session.

ParameterTypeRequiredDefaultDescription
session_idstringYes-Session ID
tool_namestringNo-Filter by tool name
limitintegerNo50Maximum results

HTTP API

GET /api/v1/sessions/{session_id}/tool-results
curl --get http://localhost:1933/api/v1/sessions/session-id/tool-results \
  -H "X-API-Key: your-key" \
  --data-urlencode "tool_name=search" \
  --data-urlencode "limit=50"

Response example

{
  "status": "ok",
  "result": {
    "tool_results": [
      {
        "tool_result_id": "tr_search_a1b2c3",
        "tool_name": "search",
        "original_chars": 48210,
        "preview_chars": 2000,
        "mime_type": "text/plain",
        "synopsis_kind": "text",
        "storage_uri": "viking://user/default/sessions/session-id/tool-results/tr_search_a1b2c3",
        "offset_unit": "unicode_code_point"
      }
    ]
  }
}

read_tool_result()

Read one externalized tool result by Unicode character range.

ParameterTypeRequiredDefaultDescription
session_idstringYes-Session ID
tool_result_idstringYes-Tool-result ID
offsetintegerNo0Starting character offset
limitintegerNo20000Maximum characters; -1 reads to the end
include_metadatabooleanNotrueInclude metadata in the response

HTTP API

GET /api/v1/sessions/{session_id}/tool-results/{tool_result_id}
curl --get http://localhost:1933/api/v1/sessions/session-id/tool-results/tool-result-id \
  -H "X-API-Key: your-key" \
  --data-urlencode "offset=0" \
  --data-urlencode "limit=20000"

Response example

{
  "status": "ok",
  "result": {
    "tool_result_id": "tr_search_a1b2c3",
    "content": "A chunk of the tool output...",
    "offset": 0,
    "limit": 20000,
    "offset_unit": "unicode_code_point",
    "total_chars": 48210,
    "has_more": true,
    "metadata": {
      "tool_name": "search",
      "mime_type": "text/plain",
      "sha256": "..."
    }
  }
}

metadata is omitted when include_metadata=false. To continue reading, set the next request's offset to the current offset plus the Unicode character count of content.

search_tool_result()

Search within one externalized tool result and return context around each match.

ParameterTypeRequiredDefaultDescription
qstringYes-Search text
limitintegerNo20Maximum matches
context_charsintegerNo300Context characters around each match

HTTP API

GET /api/v1/sessions/{session_id}/tool-results/{tool_result_id}/search?q={query}
curl --get http://localhost:1933/api/v1/sessions/session-id/tool-results/tool-result-id/search \
  -H "X-API-Key: your-key" \
  --data-urlencode "q=authentication" \
  --data-urlencode "limit=20"

Response example

{
  "status": "ok",
  "result": {
    "tool_result_id": "tr_search_a1b2c3",
    "matches": [
      {
        "offset": 1284,
        "offset_unit": "unicode_code_point",
        "snippet": "...authentication failed because..."
      }
    ]
  }
}

These endpoints are currently used by the Server and Web Studio. The public SDKs and CLI do not wrap them, so the sections above show only the HTTP tab.


get_session_context()

1. API Implementation Introduction

Get the assembled session context used for LLM context building. This endpoint returns the latest archive overview and current live messages.

Return Fields Description:

  • latest_archive_overview: The overview of the latest completed archive, when it fits the token budget
  • pre_archive_abstracts: Kept for backward compatibility, returns empty array
  • messages: All incomplete archive messages after the latest completed archive, plus current live session messages
  • estimatedTokens: Estimated total tokens
  • stats: Statistics

Token Budget Allocation Strategy:

  1. First allocate to current live messages
  2. Remaining budget prioritizes the latest archive overview
  3. Pre-archive abstracts are not currently returned

Code Entries:

  • openviking/session/session.py:Session.get_session_context() - Core implementation
  • openviking/server/routers/sessions.py:get_session_context() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.get_session_context() - Python SDK
  • crates/ov_cli/src/commands/session.rs:get_session_context() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID
token_budgetintNo128000Non-negative token budget for assembled archive payload after active messages

3. Usage Examples

HTTP API

GET /api/v1/sessions/{session_id}/context?token_budget=128000
curl -X GET "http://localhost:1933/api/v1/sessions/a1b2c3d4/context?token_budget=128000" \
  -H "X-API-Key: your-key"

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

context = await client.get_session_context("a1b2c3d4", token_budget=128000)
print(context["latest_archive_overview"])
print(len(context["messages"]))

TypeScript SDK

console.log(await client.getSessionContext("session-id"));

Go SDK

contextPayload, err := client.GetSessionContext(ctx, "a1b2c3d4", 128000)
if err != nil {
    return err
}
fmt.Println(contextPayload["latest_archive_overview"])

CLI

ov session get-session-context a1b2c3d4 --token-budget 128000

Response Example

{
  "status": "ok",
  "result": {
    "latest_archive_overview": "# Session Summary\n\n**Overview**: User discussed deployment and auth setup.",
    "pre_archive_abstracts": [],
    "messages": [
      {
        "id": "msg_pending_1",
        "role": "user",
        "parts": [
          {"type": "text", "text": "Pending user message"}
        ],
        "created_at": "2026-03-24T09:10:11Z"
      },
      {
        "id": "msg_live_1",
        "role": "assistant",
        "parts": [
          {"type": "text", "text": "Current live message"}
        ],
        "created_at": "2026-03-24T09:10:20Z"
      }
    ],
    "estimatedTokens": 160,
    "stats": {
      "totalArchives": 2,
      "includedArchives": 1,
      "droppedArchives": 0,
      "failedArchives": 0,
      "activeTokens": 98,
      "archiveTokens": 62
    }
  }
}

get_session_archive()

1. API Implementation Introduction

Get the full contents of one completed archive for a session. This endpoint is typically used with get_session_context() when you need to view older archive details.

Code Entries:

  • openviking/session/session.py:Session.get_session_archive() - Core implementation
  • openviking/server/routers/sessions.py:get_session_archive() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.get_session_archive() - Python SDK
  • crates/ov_cli/src/commands/session.rs:get_session_archive() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID
archive_idstrYes-Archive ID such as archive_002

3. Usage Examples

HTTP API

GET /api/v1/sessions/{session_id}/archives/{archive_id}
curl -X GET "http://localhost:1933/api/v1/sessions/a1b2c3d4/archives/archive_002" \
  -H "X-API-Key: your-key"

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

archive = await client.get_session_archive("a1b2c3d4", "archive_002")
print(archive["archive_id"])
print(archive["overview"])
print(len(archive["messages"]))

TypeScript SDK

console.log(await client.getSessionArchive("session-id", "archive-id"));

Go SDK

archive, err := client.GetSessionArchive(ctx, "a1b2c3d4", "archive_002")
if err != nil {
    return err
}
fmt.Println(archive["archive_id"])

CLI

ov session get-session-archive a1b2c3d4 archive_002

Response Example

{
  "status": "ok",
  "result": {
    "archive_id": "archive_002",
    "abstract": "User discussed deployment and authentication setup.",
    "overview": "# Session Summary\n\n**Overview**: User discussed deployment and auth setup.",
    "messages": [
      {
        "id": "msg_archive_1",
        "role": "user",
        "parts": [
          {"type": "text", "text": "How should I deploy this service?"}
        ],
        "created_at": "2026-03-24T08:55:01Z"
      },
      {
        "id": "msg_archive_2",
        "role": "assistant",
        "parts": [
          {"type": "text", "text": "Use the staged deployment flow and verify auth first."}
        ],
        "created_at": "2026-03-24T08:55:18Z"
      }
    ]
  }
}

Error Response

If the archive does not exist, is incomplete, or does not belong to the session, the API returns 404:

{
  "status": "error",
  "error": {
    "code": "NOT_FOUND",
    "message": "Archive archive_002 not found"
  }
}

delete_session()

1. API Implementation Introduction

Delete a session and all its data, including messages, archive history, memories, etc. Deletion is irreversible.

Code Entries:

  • openviking/server/routers/sessions.py:delete_session() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.delete_session() - Python SDK
  • crates/ov_cli/src/commands/session.rs:delete_session() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID to delete

3. Usage Examples

HTTP API

DELETE /api/v1/sessions/{session_id}
curl -X DELETE http://localhost:1933/api/v1/sessions/a1b2c3d4 \
  -H "X-API-Key: your-key"

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Delete session
await client.delete_session("a1b2c3d4")

TypeScript SDK

await client.deleteSession("session-id");

Go SDK

if err := client.DeleteSession(ctx, "a1b2c3d4"); err != nil {
    return err
}

CLI

ov session delete a1b2c3d4

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4"
  },
  "time": 0.1
}

add_message()

1. API Implementation Introduction

Add a message to the session. Supports two modes: simple text mode and Parts mode (supporting text, image URLs, context references, tool calls, etc.).

Part Types:

  • TextPart: Pure text content
  • ImagePart: OpenAI-style image URL content. During memory extraction, OpenViking can use the configured VLM to turn images into text descriptions.
  • ContextPart: Context reference pointing to resources or memories
  • ToolPart: Tool call and result

Code Entries:

  • openviking/session/session.py:Session.add_message() - Core implementation
  • openviking/server/routers/sessions.py:add_message() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.add_message() - Python SDK
  • crates/ov_cli/src/commands/session.rs:add_message() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID
rolestrYes-Message role: "user" or "assistant"
partsList[Part]Conditional-List of message parts (Required for Python SDK; Optional for HTTP API, mutually exclusive with content)
contentstrConditional-Message text content (HTTP API simple mode, mutually exclusive with parts)
created_atstrNoNoneOptional ISO 8601 timestamp to persist on the message
peer_idstrNoNoneOptional stable interaction peer identity

Note: HTTP API supports two modes:

  1. Simple mode: Use content string (backward compatible)
  2. Parts mode: Use parts array (full Part support)

If both content and parts are provided, parts takes precedence.

Part Types (Python SDK)

from openviking.message import TextPart, ImagePart, ContextPart, ToolPart

# Text content
TextPart(text="Hello, how can I help?")

# Image URL content
ImagePart(url="https://example.com/photo.png", detail="auto")

# Context reference
ContextPart(
    uri="viking://resources/docs/auth/",
    context_type="resource",  # "resource", "memory", or "skill"
    abstract="Authentication guide..."
)

# Tool call
ToolPart(
    tool_id="call_123",
    tool_name="search_web",
    skill_uri="viking://user/skills/search-web/",
    tool_input={"query": "OAuth best practices"},
    tool_output="",
    tool_status="pending"  # "pending", "running", "completed", "error"
)

3. Usage Examples

HTTP API

POST /api/v1/sessions/{session_id}/messages

Simple Mode (Backward Compatible)

# Add user message
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "role": "user",
    "content": "How do I authenticate users?"
  }'

Parts Mode (Full Part Support)

# Add assistant message with context reference
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "role": "assistant",
    "parts": [
      {"type": "text", "text": "Based on the authentication guide..."},
      {"type": "context", "uri": "viking://resources/docs/auth/", "context_type": "resource", "abstract": "Auth guide"}
    ]
  }'

# Add assistant message with tool call
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "role": "assistant",
    "parts": [
      {"type": "text", "text": "Let me search for that..."},
      {"type": "tool", "tool_id": "call_123", "tool_name": "search_web", "tool_input": {"query": "OAuth"}, "tool_status": "completed", "tool_output": "Results..."}
    ]
  }'

# Add user message with an image URL
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "role": "user",
    "parts": [
      {"type": "text", "text": "Remember this studio layout."},
      {"type": "image_url", "image_url": {"url": "https://example.com/studio.png", "detail": "auto"}}
    ]
  }'

Python SDK

import openviking as ov
from openviking.message import TextPart, ImagePart, ContextPart

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Simple mode: Add user message
await client.add_message(
    session_id="a1b2c3d4",
    role="user",
    content="How do I authenticate users?"
)

# Parts mode: Add assistant message with context reference
await client.add_message(
    session_id="a1b2c3d4",
    role="assistant",
    parts=[
        TextPart(text="Based on the documentation, you can configure embedding..."),
        ContextPart(
            uri="viking://resources/docs/auth/",
            context_type="resource",
            abstract="Authentication guide"
        )
    ]
)

# Parts mode: Add user message with an image URL
await client.add_message(
    session_id="a1b2c3d4",
    role="user",
    parts=[
        TextPart(text="Remember this studio layout."),
        ImagePart(url="https://example.com/studio.png", detail="auto"),
    ]
)

TypeScript SDK

await client.addMessage("session-id", { role: "user", content: "Hello" });

Go SDK

result, err := client.AddMessage(ctx, "a1b2c3d4", "user", openviking.AddMessageOptions{
    Content: openviking.String("How do I authenticate users?"),
    PeerID:  "web-visitor-alice",
})
if err != nil {
    return err
}
fmt.Println(result["message_count"])

CLI

ov session add-message a1b2c3d4 --role user --content "How do I authenticate users?"

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "message_count": 2
  },
  "time": 0.1
}

batch_add_messages()

1. API Implementation Introduction

Add multiple messages to a session in a single request. Suitable for scenarios that require writing a large number of messages at once (e.g., importing conversation history, memory extraction), offering significantly better performance than calling add_message() repeatedly.

Difference from add_message():

  • add_message(): Add 1 message per request
  • batch_add_messages(): Add multiple messages per request (max 100), reducing network round trips and file I/O

Code Entry Points:

  • openviking/session/session.py:Session.add_messages() - Core implementation
  • openviking/server/routers/sessions.py:batch_add_messages() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.batch_add_messages() - Python SDK
  • crates/ov_cli/src/commands/session.rs:add_messages() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID
messagesList[AddMessageRequest]Yes-List of messages, each following the same format as add_message(), max 100
telemetryboolNoFalseWhether to attach operation telemetry data

Note: Each message follows the exact same format as add_message(), supporting both content (simple mode) and parts (Parts mode). If you need to add more than 100 messages, call in batches.

3. Usage Examples

HTTP API

POST /api/v1/sessions/{session_id}/messages/batch
# Add multiple messages in batch
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages/batch \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{
    "messages": [
      {"role": "user", "content": "How do I authenticate users?"},
      {"role": "assistant", "content": "You can use OAuth 2.0 for authentication."},
      {"role": "user", "content": "Any specific recommendations?"}
    ]
  }'

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Add messages in batch
result = await client.batch_add_messages(
    session_id="a1b2c3d4",
    messages=[
        {"role": "user", "content": "How do I authenticate users?"},
        {"role": "assistant", "content": "You can use OAuth 2.0 for authentication."},
        {"role": "user", "content": "Any specific recommendations?"},
    ],
)
print(f"Added: {result['added']}, Total: {result['message_count']}")

TypeScript SDK

await client.batchAddMessages("session-id", [
  { role: "user", content: "Hello" },
  { role: "assistant", content: "Hi" },
]);

Go SDK

result, err := client.BatchAddMessages(ctx, "a1b2c3d4", []openviking.Message{
    {Role: "user", Content: openviking.String("How do I authenticate users?")},
    {Role: "assistant", Content: openviking.String("You can use OAuth 2.0 for authentication.")},
    {Role: "user", Content: openviking.String("Any specific recommendations?")},
}, nil)
if err != nil {
    return err
}
fmt.Println(result["added"], result["message_count"])

CLI

# Add multiple messages to a session
ov session add-messages a1b2c3d4 '[{"role":"user","content":"Hello"},{"role":"assistant","content":"Hi"}]'

# ov add-memory also uses the batch interface internally
ov add-memory '[{"role":"user","content":"Hello"},{"role":"assistant","content":"Hi"}]'

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "message_count": 5,
    "added": 3
  },
  "time": 0.1
}

used()

1. API Implementation Introduction

Record actually used contexts and skills in the session. When commit() is called, active_count is updated based on this usage data to optimize future retrieval ranking.

Code Entries:

  • openviking/session/session.py:Session.used() - Core implementation
  • openviking/server/routers/sessions.py:record_used() - HTTP route

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID
contextsList[str]NoNoneList of context URIs that were actually used
skillDict[str, Any]NoNoneSkill usage record with keys: uri, input, output, success

3. Usage Examples

HTTP API

POST /api/v1/sessions/{session_id}/used
# Record used contexts
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/used \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"contexts": ["viking://resources/docs/auth/"]}'

# Record used skill
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/used \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"skill": {"uri": "viking://user/skills/search-web/", "input": {"query": "OAuth"}, "output": "Results...", "success": true}}'

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "contexts_used": 1,
    "skills_used": 0
  },
  "time": 0.1
}

commit()

1. API Implementation Introduction

Commit a session. Message archiving (Phase 1) completes immediately. Summary generation and memory extraction (Phase 2) run asynchronously in the background when messages are archived. Archived commits return status: "accepted" with a task_id; no-op commits return status: "skipped" with task_id: null.

Two-Phase Commit Flow:

  • Phase 1 (Synchronous): Snapshot current messages, clear live session, create archive directory, write original messages
  • Phase 2 (Asynchronous): Generate summaries (L0/L1), extract long-term memories, update relations and active_count

Notes:

  • Rapid consecutive commits on the same session are accepted; each request gets its own task_id.
  • Empty sessions, or commits where all messages remain inside keep_recent_count, complete synchronously with archived: false.
  • Background Phase 2 work is serialized by archive order: archive N+1 waits until archive N writes .done.
  • If an earlier archive failed and left no .done, later commit requests fail with FAILED_PRECONDITION until that failure is resolved.
  • If committed messages contain durable facts, judgments, preferences, or events that mention viking://resources/..., memory extraction preserves the resource as a markdown link and records it in MEMORY_FIELDS.resource_refs.

Code Entries:

  • openviking/session/session.py:Session.commit_async() - Core implementation
  • openviking/server/routers/sessions.py:commit_session() - HTTP route
  • sdk/python/openviking_sdk/client.py:AsyncHTTPClient.commit_session() - Python SDK
  • crates/ov_cli/src/commands/session.rs:commit_session() - CLI command

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID to commit
keep_recent_countintNo0Number of recent live messages to retain (kept live, not archived) after commit. 0 (default) archives all messages.

3. Usage Examples

HTTP API

POST /api/v1/sessions/{session_id}/commit
# Commit session (returns immediately)
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/commit \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key"

# Poll task status
curl -X GET http://localhost:1933/api/v1/tasks/{task_id} \
  -H "X-API-Key: your-key"

Python SDK

import openviking as ov

client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Commit returns immediately with task_id; summary + memory extraction runs in background
result = await client.commit_session("a1b2c3d4")
print(f"Status: {result['status']}")
print(f"Task ID: {result['task_id']}")

# Poll background task status
task = await client.get_task(result["task_id"])
if task["status"] == "completed":
    memories = task["result"]["memories_extracted"]
    total = sum(memories.values())
    print(f"Memories extracted: {total}")

TypeScript SDK

console.log(await client.commitSession("session-id"));

Go SDK

commit, err := client.CommitSession(ctx, "a1b2c3d4", &openviking.CommitSessionOptions{
    KeepRecentCount: 0,
})
if err != nil {
    return err
}
fmt.Println(commit["status"], commit["task_id"])

taskID, _ := commit["task_id"].(string)
task, err := client.GetTask(ctx, taskID)
if err != nil {
    return err
}
fmt.Println(task["status"])

CLI

ov session commit a1b2c3d4

Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "status": "accepted",
    "task_id": "uuid-xxx",
    "archive_uri": "viking://user/alice/sessions/a1b2c3d4/history/archive_001",
    "archived": true
  }
}

No-op Response Example

{
  "status": "ok",
  "result": {
    "session_id": "a1b2c3d4",
    "status": "skipped",
    "task_id": null,
    "archive_uri": null,
    "archived": false,
    "reason": "no_messages"
  }
}

extract()

1. API Implementation Introduction

Trigger memory extraction immediately for an existing session without creating a new commit task.

Code Entries:

  • openviking/server/routers/sessions.py:extract_session() - HTTP route

2. Interface and Parameter Description

Parameters

ParameterTypeRequiredDefaultDescription
session_idstrYes-Session ID to extract memories from

3. Usage Examples

HTTP API

POST /api/v1/sessions/{session_id}/extract
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/extract \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key"

Response Example

The endpoint returns the extracted memory write results as a JSON list. The exact item shape depends on which memories were produced for that session.

Session Properties

PropertyTypeDescription
uristrSession Viking URI (viking://user/{user_id}/sessions/{session_id}/)
messagesList[Message]Current messages in the session
statsSessionStatsSession statistics
summarystrCompression summary
usage_recordsList[Usage]Context and skill usage records

Session Storage Structure

viking://user/{user_id}/sessions/{session_id}/
+-- .abstract.md              # L0: Session overview
+-- .overview.md              # L1: Key decisions
+-- messages.jsonl            # Current messages
+-- tools/                    # Tool executions
|   +-- {tool_id}/
|       +-- tool.json
+-- .meta.json                # Metadata
+-- .relations.json           # Related contexts
+-- history/                  # Archived history
    +-- archive_001/
    |   +-- messages.jsonl    # Written in Phase 1
    |   +-- .abstract.md      # Written in Phase 2 (background)
    |   +-- .overview.md      # Written in Phase 2 (background)
    |   +-- .meta.json        # Archive metadata
    |   +-- memory_diff.json  # Written when long-term memory extraction completes
    |   +-- .done             # Phase 2 completion marker
    |   +-- .failed.json      # Phase 2 failure marker
    +-- archive_002/

memory_diff.json Structure

When long-term memory extraction runs successfully, the commit writes a memory_diff.json to the archive directory, recording all memory changes 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
  }
}
FieldTypeDescription
archive_uristrArchive directory URI for this commit
extracted_atstrISO 8601 timestamp of extraction
operations.addsarrayNew memories created (uri, memory_type, after)
operations.updatesarrayModified memories (uri, memory_type, before, after)
operations.deletesarrayDeleted memories (uri, memory_type, deleted_content)
summary.total_addsintNumber of new memories
summary.total_updatesintNumber of modified memories
summary.total_deletesintNumber of deleted memories

An empty memory_diff.json (all counts zero) is written when long-term memory extraction runs but produces no memory operations.

Full Example

Python SDK

import openviking as ov
from openviking.message import TextPart, ContextPart

# Initialize client
client = ov.Client(base_url="http://localhost:1933", api_key="your-key")

# Create new session
session_result = await client.create_session()
session_id = session_result["session_id"]
print(f"Session created: {session_id}")

# Add user message
await client.add_message(
    session_id=session_id,
    role="user",
    content="How do I configure embedding?"
)

# Search with session context
results = await client.search("embedding configuration", session_id=session_id)

# Add assistant message with context reference
if results.resources:
    await client.add_message(
        session_id=session_id,
        role="assistant",
        parts=[
            TextPart(text="Based on the documentation, you can configure embedding..."),
            ContextPart(
                uri=results.resources[0].uri,
                context_type="resource",
                abstract=results.resources[0].abstract
            )
        ]
    )
# Commit session (returns immediately; summary + memory extraction runs in background)
commit_result = await client.commit_session(session_id)
print(f"Task ID: {commit_result['task_id']}")

# Optional: poll for completion
task = await client.get_task(commit_result["task_id"])
if task and task["status"] == "completed":
    memories = task["result"]["memories_extracted"]
    total = sum(memories.values())
    print(f"Memories extracted: {total}")

HTTP API

# Step 1: Create session
curl -X POST http://localhost:1933/api/v1/sessions \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key"
# Returns: {"status": "ok", "result": {"session_id": "a1b2c3d4"}}

# Step 2: Add user message
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"role": "user", "content": "How do I configure embedding?"}'

# Step 3: Search with session context
curl -X POST http://localhost:1933/api/v1/search/search \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"query": "embedding configuration", "session_id": "a1b2c3d4"}'

# Step 4: Add assistant message
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/messages \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"role": "assistant", "content": "Based on the documentation, you can configure embedding..."}'

# Step 5: Record used contexts
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/used \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key" \
  -d '{"contexts": ["viking://resources/docs/embedding/"]}'

# Step 6: Commit session (returns immediately with task_id)
curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/commit \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-key"
# Returns: {"status": "ok", "result": {"status": "accepted", "task_id": "uuid-xxx", ...}}

# Step 7: Poll background task status (optional)
curl -X GET http://localhost:1933/api/v1/tasks/uuid-xxx \
  -H "X-API-Key: your-key"

Best Practices

Commit Regularly

# Commit after significant interactions
session_info = await client.get_session(session_id)
if session_info["message_count"] > 10:
    await client.commit_session(session_id)
# Better search results with conversation context
results = await client.search(query, session_id=session_id)