Sessions
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:
- Generate or use provided session_id
- Initialize session metadata (creation time, user info, etc.)
- Create session directory structure in storage
- Return session info
Code Entries:
openviking/session/session.py:Session.__init__()- Core Session classopenviking/session/auto_commit_policy.py:AutoCommitPolicy- Auto-commit policy defaults and validationopenviking/server/routers/sessions.py:create_session()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.create_session()- Python SDKcrates/ov_cli/src/commands/session.rs:new_session()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | No | None | Session ID. Creates new session with auto-generated ID if None |
| memory_policy | object | No | None | Default memory extraction policy for the session. Optional self and peer switches control write targets, working_memory.enabled defaults to false (no archive/checkpoint summaries); explicitly set it to true to generate 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_policy | object | No | None | Optional 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 omitted, the new Session inherits server.user_config_defaults.auto_commit_policy, then the existing memory.session_auto_commit.enabled behavior. 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):
| Field | Type | Default | Min | Max | Description |
|---|---|---|---|---|---|
pending_token_threshold | int | 150000 | 0 | 1000000 | When uncommitted pending tokens exceed this value (strictly greater-than), an auto commit is triggered after a message write. |
message_count_threshold | int | 100 | 0 | 1000 | When the uncommitted live message count exceeds this value (strictly greater-than), an auto commit is triggered after a message write. |
idle_timeout_seconds | int | 86400 | 0 (off) or 300 | 604800 | After 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_count | int | 0 | 0 | 500 | Number 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_seconds | int | 0 | 0 | 604800 | Minimum seconds between two automatic commits (throttle). |
New idle_timeout_seconds inputs must be 0 (off) or at least 300; values above 604800 are clamped to that maximum. For stored-data compatibility, existing positive values below 300 continue to be read unchanged. Other fields have a minimum of 0 and are clamped to their ranges. Unknown keys are rejected with InvalidArgumentError. Idle commits also require memory.session_auto_commit.enabled on the server; setting idle_timeout_seconds alone does not start the scanner.
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_sdk as ov
# Use HTTP client
client = ov.SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
# Create new session (auto-generated ID)
result = client.create_session()
print(f"Session ID: {result['session_id']}")
# Create new session with specified ID
result = 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 = client.create_session(
options={
"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 newResponse Example
{
"status": "ok",
"result": {
"session_id": "a1b2c3d4",
"uri": "viking://user/alice/sessions/a1b2c3d4",
"user": {
"account_id": "default",
"user_id": "alice"
},
"auto_commit_policy": null
}
}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 routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.list_sessions()- Python SDKcrates/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/sessionscurl -X GET http://localhost:1933/api/v1/sessions \
-H "X-API-Key: your-key"Python SDK
from openviking_sdk import SyncHTTPClient
client = SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
sessions = 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 listResponse 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
}
]
}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 messagestotal_message_count: Cumulative count of archived and current live messages (older sessions may omit this field)commit_count: Number of successful commitsmemories_extracted: Count statistics of extracted memories by categorylast_commit_at: Time of last commitauto_commit_policy: Effective auto-commit policy with defaults filled in;nullwhen not enabled
Code Entries:
openviking/session/session.py:Session.load()- Session loadingopenviking/server/routers/sessions.py:get_session()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.get_session()- Python SDKcrates/ov_cli/src/commands/session.rs:get_session()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | Session ID |
| auto_create | bool | No | False | Whether to auto-create the session if it does not exist |
3. Usage Examples
HTTP API
GET /api/v1/sessions/{session_id}?auto_create=falsecurl -X GET http://localhost:1933/api/v1/sessions/a1b2c3d4 \
-H "X-API-Key: your-key"Python SDK
from openviking_sdk import SyncHTTPClient
client = SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
# Get existing session (raises NotFoundError if not found)
info = client.get_session(session_id="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 = client.get_session(session_id="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 a1b2c3d4Response 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": 150000,
"message_count_threshold": 100,
"idle_timeout_seconds": 86400,
"keep_recent_count": 0,
"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 routeopenviking/service/session_service.py:SessionService.update_config()- Config validation and updatesdk/python/openviking_sdk/client.py:update_session_config()- Python SDKsdk/typescript/src/client.ts:updateSessionConfig()- TypeScript SDKsdk/go/sessions.go:UpdateSessionConfig()- Go SDKcrates/ov_cli/src/commands/session.rs:set_session_config()- CLI command
2. Interface and Parameter Description
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | string | Yes | - | Session ID in the URL path |
| memory_extraction_config | object | No | Omitted | Mutable 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_policy | object or null | No | Omitted | An 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. |
| telemetry | boolean or object | No | false | Set 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(
session_id="a1b2c3d4",
options={
"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-commitResponse example
{
"status": "ok",
"result": {
"session_id": "a1b2c3d4",
"auto_commit_policy": {
"pending_token_threshold": 150000,
"message_count_threshold": 25,
"idle_timeout_seconds": 86400,
"keep_recent_count": 0,
"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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
session_id | string | Yes | - | Session ID |
tool_name | string | No | - | Filter by tool name |
limit | integer | No | 50 | Maximum results |
HTTP API
GET /api/v1/sessions/{session_id}/tool-resultscurl --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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
session_id | string | Yes | - | Session ID |
tool_result_id | string | Yes | - | Tool-result ID |
offset | integer | No | 0 | Starting character offset |
limit | integer | No | 20000 | Maximum characters; -1 reads to the end |
include_metadata | boolean | No | true | Include 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.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
q | string | Yes | - | Search text |
limit | integer | No | 20 | Maximum matches |
context_chars | integer | No | 300 | Context 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: Theoverviewof the latest completed archive, when it fits the token budgetpre_archive_abstracts: Kept for backward compatibility, returns empty arraymessages: Incomplete archive messages after the latest completed archive and current live messages, limited to the token budgetestimatedTokens: Estimated total tokensstats: Statistics.includedArchivescounts entries inpre_archive_abstracts, which is currently empty; checklatest_archive_overviewitself to see whether an overview is included
Token Budget Allocation Strategy:
- Fit the messages into the budget first, dropping or truncating messages when needed, then calculate the remaining budget
- Remaining budget prioritizes the latest archive overview
- Pre-archive abstracts are not currently returned
Code Entries:
openviking/session/session.py:Session.get_session_context()- Core implementationopenviking/server/routers/sessions.py:get_session_context()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.get_session_context()- Python SDKcrates/ov_cli/src/commands/session.rs:get_session_context()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | Session ID |
| token_budget | int | No | 128000 | Non-negative budget for the entire returned context; messages are budgeted first, then the archive overview uses the remainder |
3. Usage Examples
HTTP API
GET /api/v1/sessions/{session_id}/context?token_budget=128000curl -X GET "http://localhost:1933/api/v1/sessions/a1b2c3d4/context?token_budget=128000" \
-H "X-API-Key: your-key"Python SDK
from openviking_sdk import SyncHTTPClient
client = SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
context = client.get_session_context(session_id="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 128000Response 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": 29,
"stats": {
"totalArchives": 2,
"includedArchives": 0,
"droppedArchives": 2,
"failedArchives": 0,
"activeTokens": 10,
"archiveTokens": 19
}
}
}get_session_archive()
1. API Implementation Introduction
Get the full contents of one completed archive for a session. A normal WM-disabled archive returns its raw messages with empty abstract and overview; no summary is generated on read. Pending, failed, missing, or corrupt archives retain their existing error behavior. This explicit history read is independent of the bounded get_session_context() prompt view.
Code Entries:
openviking/session/session.py:Session.get_session_archive()- Core implementationopenviking/server/routers/sessions.py:get_session_archive()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.get_session_archive()- Python SDKcrates/ov_cli/src/commands/session.rs:get_session_archive()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | Session ID |
| archive_id | str | Yes | - | 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_sdk as ov
client = ov.SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
archive = client.get_session_archive(
session_id="a1b2c3d4",
archive_id="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_002Response 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 the session directory, including messages, archives, and session audit records. Long-term memories already extracted into user or Peer memory directories remain; locate and delete those URIs separately when needed. This endpoint has no automatic undo.
Code Entries:
openviking/server/routers/sessions.py:delete_session()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.delete_session()- Python SDKcrates/ov_cli/src/commands/session.rs:delete_session()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | 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_sdk as ov
client = ov.SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
# Delete session
client.delete_session(session_id="a1b2c3d4")TypeScript SDK
await client.deleteSession("session-id");Go SDK
if err := client.DeleteSession(ctx, "a1b2c3d4"); err != nil {
return err
}CLI
ov session delete a1b2c3d4Response Example
{
"status": "ok",
"result": {
"session_id": "a1b2c3d4"
}
}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 contentImagePart: 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 memoriesToolPart: Tool call and result
Code Entries:
openviking/session/session.py:Session.add_message()- Core implementationopenviking/server/routers/sessions.py:add_message()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.add_message()- Python SDKcrates/ov_cli/src/commands/session.rs:add_message()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | Session ID |
| role | str | Yes | - | Message role: "user" or "assistant" |
| parts | List[dict | MessagePart] | Conditional | - | SDK part dictionaries or TextPart/ContextPart/ImagePart/ToolPart objects; HTTP API accepts dictionaries only; use instead of content |
| content | str | Conditional | - | Message text content (simple mode; use instead of parts) |
| peer_id | str | No | None | Optional stable interaction peer identity |
| options | AddMessageOptions | No | None | Advanced message options such as created_at, telemetry, turn_id, message_kind, and source_message_ids |
Note: HTTP API supports two modes:
- Simple mode: Use
contentstring (backward compatible)- Parts mode: Use
partsarray (full Part support)If both
contentandpartsare provided,partstakes precedence.
Part Types (Python SDK)
from openviking_sdk import ContextPart, ImagePart, TextPart, 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://~/skills/search-web/",
tool_input={"query": "OAuth best practices"},
tool_status="pending", # "pending", "running", "completed", "error"
)You can also pass the equivalent dictionaries when you need to share the same payload shape with HTTP, Go, or TypeScript code.
3. Usage Examples
HTTP API
POST /api/v1/sessions/{session_id}/messagesSimple 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_sdk as ov
from openviking_sdk import ContextPart, ImagePart, TextPart
client = ov.SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
# Simple mode: Add user message
client.add_message(
session_id="a1b2c3d4",
role="user",
content="How do I authenticate users?",
)
# Parts mode: Add assistant message with context reference
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
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
}
}batch_add_messages()
1. API Implementation Introduction
Add multiple messages to a session in one request, for example when importing conversation history. Batching reduces the number of requests compared with calling add_message() for each message.
Difference from add_message():
add_message(): Add 1 message per requestbatch_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 implementationopenviking/server/routers/sessions.py:batch_add_messages()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.batch_add_messages()- Python SDKcrates/ov_cli/src/commands/session.rs:add_messages()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | Session ID |
| messages | List[AddMessageRequest] | Yes | - | List of messages, each following the same format as add_message(), max 100 |
| options | BatchAddMessagesOptions | No | None | Advanced batch options such as telemetry; pass options={"telemetry": True} to include operation telemetry data |
Note: Each message follows the exact same format as
add_message(), supporting bothcontent(simple mode) andparts(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
from openviking_sdk import SyncHTTPClient
client = SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
# Add messages in batch
result = 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
}
}commit()
1. API Implementation Introduction
Commit a session. Message archiving (Phase 1) completes before the response returns. 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.
The former standalone session extract endpoint has been removed. Use commit for memory extraction. This archives messages according to the retention policy; use the returned task_id to check the background extraction result. An accepted response does not mean extraction is complete.
Two-Phase Commit Flow:
- Phase 1 (Synchronous): Split messages according to the retention policy, persist the archive and recovery records, enqueue Phase 2, and write retained messages back to the live session
- Phase 2 (Asynchronous): Extract long-term memories; generate WM/checkpoint summaries only when the effective WM policy is enabled (default: disabled)
Notes:
- Consecutive commits are accepted; only requests that produce an archive return a separate
task_id. No-op commits do not create tasks. - Empty sessions, or commits where all messages remain inside
keep_recent_count, complete synchronously witharchived: false. - Background Phase 2 work is serialized by archive order: archive
N+1waits until archiveNwrites.done. - If an earlier archive failed and left no
.done, later commit requests fail withFAILED_PRECONDITIONuntil 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 inMEMORY_FIELDS.resource_refs.
Code Entries:
openviking/session/session.py:Session.commit_async()- Core implementationopenviking/server/routers/sessions.py:commit_session()- HTTP routesdk/python/openviking_sdk/client.py:AsyncHTTPClient.commit_session()- Python SDKcrates/ov_cli/src/commands/session.rs:commit_session()- CLI command
2. Interface and Parameter Description
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| session_id | str | Yes | - | Session ID to commit |
| keep_recent_count | int | No | 0 | Number of recent live messages to retain (kept live, not archived) after commit. 0 (default) archives all messages. |
| enable_working_memory | bool or null | No | null | Override only WM generation for this commit. Omitted/null inherits the resolved policy; true/false leaves self/peer/memory_types and saved policies unchanged. Strings/numbers are rejected. The response includes effective_enable_working_memory. |
| reset_context | bool | No | false | HTTP API: archive all live messages, then append a boundary archive containing only a .done marker with context_reset. Keeps the session ID and raw history, clears injected context and stops future summaries from inheriting pre-reset overviews. Requires keep_recent_count=0 and no retention_mode. |
reset_context is used by the OpenClaw plugin reset hook and Session.commit_async(). It also creates a boundary when there are no live messages, unless the newest archive is already a reset boundary. Memory extraction for older archives can finish independently; long-term memories are preserved. The SDK and CLI do not expose a dedicated reset_context option; use the HTTP API when needed.
The effective policy is resolved in this order: Session .meta.json, latest settings/user_config.json, then the kernel default. The fully resolved policy is stored in the queued task before Phase 2 starts.
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_sdk as ov
client = ov.SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
# Commit finishes Phase 1; summary and memory extraction run in the background
result = client.commit_session(session_id="a1b2c3d4")
print(f"Status: {result['status']}")
print(f"Task ID: {result['task_id']}")
# Check once; poll again if the task is still pending or running
task_id = result.get("task_id")
if task_id:
task = client.get_task(task_id=task_id)
print(task["status"])
if task["status"] == "completed":
print(task["result"]["memories_extracted"])TypeScript SDK
console.log(await client.commitSession("session-id"));Go SDK
commit, err := client.CommitSession(ctx, "a1b2c3d4", &openviking.CommitSessionOptions{
KeepRecentCount: openviking.Int(0),
})
if err != nil {
return err
}
fmt.Println(commit["status"], commit["task_id"])
taskID, _ := commit["task_id"].(string)
if taskID != "" {
task, err := client.GetTask(ctx, taskID)
if err != nil {
return err
}
fmt.Println(task["status"])
}CLI
ov session commit a1b2c3d4Response 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"
}
}Session Properties
| Property | Type | Description |
|---|---|---|
| uri | str | Session Viking URI (viking://user/{user_id}/sessions/{session_id}/) |
| messages | List[Message] | Current messages in the session |
| stats | SessionStats | Session statistics |
| summary | str | Compression summary |
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
+-- 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 reviewing changes:
{
"archive_uri": "viking://user/{user_id}/sessions/{session_id}/history/archive_001",
"extracted_at": "2026-04-21T10:00:00Z",
"operations": {
"adds": [
{
"uri": "viking://user/alice/memories/profile.md",
"memory_type": "profile",
"after": "Newly created file content"
}
],
"updates": [
{
"uri": "viking://user/alice/memories/preferences/project.md",
"memory_type": "preferences",
"before": "Content before modification",
"after": "Content after modification"
}
],
"deletes": [
{
"uri": "viking://user/alice/memories/preferences/old.md",
"memory_type": "preferences",
"deleted_content": "Deleted file content"
}
]
},
"skipped_operations": [
{
"memory_type": "events",
"page_id": 101,
"reason_code": "invalid_ranges",
"reason": "No valid event range could be resolved"
}
],
"summary": {
"total_adds": 1,
"total_updates": 1,
"total_deletes": 1,
"total_skipped": 1
}
}| Field | Type | Description |
|---|---|---|
archive_uri | str | Archive directory URI for this commit |
extracted_at | str | ISO 8601 timestamp of extraction |
operations.adds | array | New memories created (uri, memory_type, after) |
operations.updates | array | Modified memories (uri, memory_type, before, after) |
operations.deletes | array | Deleted memories (uri, memory_type, deleted_content) |
skipped_operations | array | Intentionally skipped operations and their stable reason codes; these do not represent file changes |
summary.total_adds | int | Number of new memories |
summary.total_updates | int | Number of modified memories |
summary.total_deletes | int | Number of deleted memories |
summary.total_skipped | int | Number of intentionally skipped operations |
An empty memory_diff.json (all counts zero) is written when long-term memory extraction runs but produces no applied or intentionally skipped operations.
Full Example
Python SDK
import time
from openviking_sdk import SyncHTTPClient, ContextPart, TextPart
# Initialize client
client = SyncHTTPClient(url="http://localhost:1933", api_key="your-key")
client.initialize()
try:
# Create new session
session_result = client.create_session()
session_id = session_result["session_id"]
print(f"Session created: {session_id}")
# Add user message
client.add_message(
session_id=session_id,
role="user",
content="How do I configure embedding?",
)
# Search with session context
results = client.search(
query="embedding configuration",
session_id=session_id,
)
# Add assistant message with context reference
resources = results.get("resources", [])
if resources:
resource = resources[0]
client.add_message(
session_id=session_id,
role="assistant",
parts=[
TextPart(text="Based on the documentation, you can configure embedding..."),
ContextPart(
uri=resource["uri"],
context_type="resource",
abstract=resource.get("abstract", ""),
),
],
)
# Commit session; summary and memory extraction run in the background
commit_result = client.commit_session(session_id=session_id)
print(f"Task ID: {commit_result['task_id']}")
# Optional: poll for completion
task_id = commit_result.get("task_id")
if task_id:
for _ in range(30):
task = client.get_task(task_id=task_id)
if task and task["status"] == "completed":
print(task.get("result"))
break
if task and task["status"] in {"failed", "cancelled"}:
raise RuntimeError(task)
time.sleep(1)
else:
print(f"Still pending: {task_id}; check this task again later")
finally:
client.close()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: Commit session (an archived commit returns a 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 6: Check the background task; poll again if it has not finished
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 = client.get_session(session_id=session_id)
if session_info["message_count"] > 10:
client.commit_session(session_id=session_id)Use Session Context for Search
# Interpret the query using session context; results depend on relevance and query-planning settings
results = client.search(query=query, session_id=session_id)Related Documentation
- Context Types - Memory types
- Memory - memory types and type-quota recall
- Retrieval - Search with session
- Resources - Resource management
- Background Tasks - track commit tasks