# 会话 会话用于管理对话状态、跟踪上下文使用情况,并提取长期记忆。会话采用分层存储(L0/L1/L2)来优化 token 使用: - L0(abstract): 会话概览摘要 - L1(overview): 关键决策和总结 - L2(messages): 完整消息 会话存储在当前用户命名空间下: ```text viking://user/{user_id}/sessions/{session_id} ``` Session API 按认证用户作用域访问会话,并返回 canonical user session URI。 基于 URI 的 API 也可以接受向后兼容的 `viking://session/{session_id}` 别名, 该别名会在同一个用户上下文中解析。 ## API 参考 ### create_session() #### 1. API 实现介绍 创建新会话。会话是对话的容器,用于存储消息、跟踪上下文使用情况,并支持提交以提取长期记忆。 **处理流程**: 1. 生成或使用提供的 session_id 2. 初始化会话元数据(创建时间、用户信息等) 3. 在存储中创建会话目录结构 4. 返回会话信息 **代码入口**: - `openviking/session/session.py:Session.__init__()` - Session 核心类 - `openviking/session/auto_commit_policy.py:AutoCommitPolicy` - 自动 commit 策略的默认值与校验 - `openviking/server/routers/sessions.py:create_session()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.create_session()` - Python SDK - `crates/ov_cli/src/commands/session.rs:new_session()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 否 | None | 会话 ID。如果为 None,则创建一个自动生成 ID 的新会话 | | memory_policy | object | 否 | None | 会话默认的记忆抽取策略。可选的 `self` 和 `peer` 开关控制写入目标;可选的 `working_memory.enabled=false` 跳过 archive summary;可选的顶层 `memory_types` 将抽取限制为指定的 enabled memory schema。所有 `enabled` 值都应使用 JSON 布尔值。旧版 boolean-like 值暂时仍兼容(字符串 `"false"` 会正确解析为 false),但会产生弃用警告。未传或为 `null` 时允许所有 enabled memory schema。非法结构或未知 memory type 会以 `InvalidArgumentError` 拒绝。 | | auto_commit_policy | object | 否 | None | 可选的自动 commit 策略(见下表)。传入的字段会被校验并 clamp 到取值范围,然后合并到默认值之上;最终生效的策略会在响应的 `result.auto_commit_policy` 中返回,并持久化到 session meta。未传 policy 时 auto commit 关闭,除非 `memory.session_auto_commit.default_enabled=true`。该策略创建后不可变。 | `auto_commit_policy` 字段(均为可选;存在 policy 时,未传字段回退到默认值): | 字段 | 类型 | 默认值 | 上限 | 说明 | |------|------|--------|------|------| | `pending_token_threshold` | int | 10000 | 50000 | 当未提交的 pending token 超过该值(严格大于)时,会在消息写入后触发一次自动 commit。 | | `message_count_threshold` | int | 50 | 500 | 当未提交的 live message 数量超过该值(严格大于)时,会在消息写入后触发一次自动 commit。 | | `idle_timeout_seconds` | int | 86400 | 604800 | 有未提交内容的 session 在空闲这么多秒后,进入服务端 idle scheduler 的处理范围。idle 触发的 commit 会归档全部积压消息,并忽略 `keep_recent_count`。 | | `keep_recent_count` | int | 2 | 500 | 阈值触发的自动 commit 后保留(不归档)的最近 live message 数量。idle 超时触发的 commit 会忽略该值并归档所有消息。 | | `min_commit_interval_seconds` | int | 0 | 604800 | 两次自动 commit 之间的最小间隔秒数(节流)。 | 所有字段最小值为 `0`,会被 clamp 到 `[0, 上限]`。未知字段会以 `InvalidArgumentError` 拒绝。 #### 3. 使用示例 **HTTP API** ```http POST /api/v1/sessions ``` ```bash # 创建新会话(自动生成 ID) curl -X POST http://localhost:1933/api/v1/sessions \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" # 创建指定 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"}' # 创建带自定义自动 commit 策略的新会话 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** ```python import openviking as ov # 使用 HTTP 客户端 client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # 创建新会话(自动生成 ID) result = await client.create_session() print(f"Session ID: {result['session_id']}") # 创建指定 ID 的新会话 result = await client.create_session(session_id="my-custom-session-id") print(f"Session ID: {result['session_id']}") # 创建带自定义自动 commit 策略的新会话 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** ```typescript const session = await client.createSession(); console.log(session); ``` **Go SDK** ```go session, err := client.CreateSession(ctx, &openviking.CreateSessionOptions{ SessionID: "my-custom-session-id", }) if err != nil { return err } fmt.Println(session["session_id"]) ``` **CLI** ```bash ov session new ``` **响应示例** ```json { "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 实现介绍 列出当前用户的所有会话。返回会话 ID 和 URI 信息,用于进一步操作会话。 **代码入口**: - `openviking/server/routers/sessions.py:list_sessions()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.list_sessions()` - Python SDK - `crates/ov_cli/src/commands/session.rs:list_sessions()` - CLI 命令 #### 2. 接口和参数说明 **参数** 无参数。 #### 3. 使用示例 **HTTP API** ```http GET /api/v1/sessions ``` ```bash curl -X GET http://localhost:1933/api/v1/sessions \ -H "X-API-Key: your-key" ``` **Python SDK** ```python 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** ```typescript console.log(await client.listSessions()); ``` **Go SDK** ```go sessions, err := client.ListSessions(ctx) if err != nil { return err } for _, session := range sessions { fmt.Println(session) } ``` **CLI** ```bash ov session list ``` **响应示例** ```json { "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 实现介绍 获取会话详情,包括元数据、消息统计、提交历史等。支持在会话不存在时自动创建。 **返回字段说明**: - `message_count`: 当前 live session 中尚未归档的消息数 - `total_message_count`: 已归档消息与当前 live 消息的累计总数(旧会话可能不返回此字段) - `commit_count`: 成功提交的次数 - `memories_extracted`: 各类记忆的提取数量统计 - `last_commit_at`: 最后一次提交的时间 - `auto_commit_policy`: 填充默认值后的生效自动 commit 策略;未启用时为 `null` **代码入口**: - `openviking/session/session.py:Session.load()` - 会话加载 - `openviking/server/routers/sessions.py:get_session()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.get_session()` - Python SDK - `crates/ov_cli/src/commands/session.rs:get_session()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 会话 ID | | auto_create | bool | 否 | False | 会话不存在时是否自动创建 | #### 3. 使用示例 **HTTP API** ```http GET /api/v1/sessions/{session_id}?auto_create=false ``` ```bash curl -X GET http://localhost:1933/api/v1/sessions/a1b2c3d4 \ -H "X-API-Key: your-key" ``` **Python SDK** ```python import openviking as ov client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # 获取已有会话(不存在时抛 NotFoundError) 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']}") # 获取或创建会话 info = await client.get_session("a1b2c3d4", auto_create=True) ``` **TypeScript SDK** ```typescript console.log(await client.getSession("session-id")); ``` **Go SDK** ```go // 获取已有会话 info, err := client.GetSession(ctx, "a1b2c3d4", nil) if err != nil { return err } fmt.Println(info["message_count"]) // 获取或创建会话 info, err = client.GetSession(ctx, "a1b2c3d4", &openviking.GetSessionOptions{ AutoCreate: true, }) if err != nil { return err } fmt.Println(info["session_id"]) ``` **CLI** ```bash ov session get a1b2c3d4 ``` **响应示例** ```json { "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 } } } ``` --- ### 更新 Session 配置 自动 commit 策略创建后不可变。请在创建 session 时设置 `auto_commit_policy`,之后通过 `GET /api/v1/sessions/{session_id}` 查看生效配置。 Sessions API 不提供运行期 session 配置更新接口。 --- ### list_tool_results() 列出会话中因体积较大而外置保存的工具结果。 | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `session_id` | string | 是 | - | 会话 ID | | `tool_name` | string | 否 | - | 按工具名过滤 | | `limit` | integer | 否 | `50` | 最大返回数量 | **HTTP API** ```http GET /api/v1/sessions/{session_id}/tool-results ``` ```bash 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" ``` **响应示例** ```json { "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() 按 Unicode 字符范围读取一个外置工具结果。 | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `session_id` | string | 是 | - | 会话 ID | | `tool_result_id` | string | 是 | - | 工具结果 ID | | `offset` | integer | 否 | `0` | 起始字符位置 | | `limit` | integer | 否 | `20000` | 最大字符数;`-1` 表示读取到结尾 | | `include_metadata` | boolean | 否 | `true` | 是否返回元数据 | **HTTP API** ```http GET /api/v1/sessions/{session_id}/tool-results/{tool_result_id} ``` ```bash 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" ``` **响应示例** ```json { "status": "ok", "result": { "tool_result_id": "tr_search_a1b2c3", "content": "工具返回的文本片段……", "offset": 0, "limit": 20000, "offset_unit": "unicode_code_point", "total_chars": 48210, "has_more": true, "metadata": { "tool_name": "search", "mime_type": "text/plain", "sha256": "..." } } } ``` `include_metadata=false` 时省略 `metadata`。继续读取时,将下一次请求的 `offset` 设为当前 `offset` 加上 `content` 的 Unicode 字符数。 ### search_tool_result() 在一个外置工具结果中搜索文本,并返回命中位置附近的上下文。 | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | `q` | string | 是 | - | 搜索文本 | | `limit` | integer | 否 | `20` | 最大命中数 | | `context_chars` | integer | 否 | `300` | 每个命中前后的上下文字符数 | **HTTP API** ```http GET /api/v1/sessions/{session_id}/tool-results/{tool_result_id}/search?q={query} ``` ```bash 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" ``` **响应示例** ```json { "status": "ok", "result": { "tool_result_id": "tr_search_a1b2c3", "matches": [ { "offset": 1284, "offset_unit": "unicode_code_point", "snippet": "...authentication failed because..." } ] } } ``` 外置工具结果端点当前由 Server 和 Web Studio 使用,公共 SDK 与 CLI 暂未提供封装,因此以上小节只展示 HTTP Tab。 --- ### get_session_context() #### 1. API 实现介绍 获取供上下文组装使用的会话上下文。该接口返回最新的归档摘要和当前活跃消息,用于 LLM 上下文构建。 **返回字段说明**: - `latest_archive_overview`: 最新一个已完成归档的 overview 文本,在 token budget 足够时返回 - `pre_archive_abstracts`: 保持 API 向下兼容,返回空数组 - `messages`: 最新已完成归档之后的所有未完成归档消息,再加上当前 live session 消息 - `estimatedTokens`: 预估总 token 数 - `stats`: 统计信息 **token budget 分配策略**: 1. 先分配给当前活跃消息 2. 剩余预算优先给最新归档的 overview 3. pre_archive_abstracts 目前不返回 **代码入口**: - `openviking/session/session.py:Session.get_session_context()` - 核心实现 - `openviking/server/routers/sessions.py:get_session_context()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.get_session_context()` - Python SDK - `crates/ov_cli/src/commands/session.rs:get_session_context()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 会话 ID | | token_budget | int | 否 | 128000 | active messages 之后留给 assembled archive payload 的非负 token 预算 | #### 3. 使用示例 **HTTP API** ```http GET /api/v1/sessions/{session_id}/context?token_budget=128000 ``` ```bash curl -X GET "http://localhost:1933/api/v1/sessions/a1b2c3d4/context?token_budget=128000" \ -H "X-API-Key: your-key" ``` **Python SDK** ```python 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** ```typescript console.log(await client.getSessionContext("session-id")); ``` **Go SDK** ```go contextPayload, err := client.GetSessionContext(ctx, "a1b2c3d4", 128000) if err != nil { return err } fmt.Println(contextPayload["latest_archive_overview"]) ``` **CLI** ```bash ov session get-session-context a1b2c3d4 --token-budget 128000 ``` **响应示例** ```json { "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 实现介绍 获取某次已完成归档的完整内容。该接口通常配合 `get_session_context()` 使用,当需要查看更早的归档详情时调用。 **代码入口**: - `openviking/session/session.py:Session.get_session_archive()` - 核心实现 - `openviking/server/routers/sessions.py:get_session_archive()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.get_session_archive()` - Python SDK - `crates/ov_cli/src/commands/session.rs:get_session_archive()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 会话 ID | | archive_id | str | 是 | - | 归档 ID,例如 `archive_002` | #### 3. 使用示例 **HTTP API** ```http GET /api/v1/sessions/{session_id}/archives/{archive_id} ``` ```bash curl -X GET "http://localhost:1933/api/v1/sessions/a1b2c3d4/archives/archive_002" \ -H "X-API-Key: your-key" ``` **Python SDK** ```python 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** ```typescript console.log(await client.getSessionArchive("session-id", "archive-id")); ``` **Go SDK** ```go archive, err := client.GetSessionArchive(ctx, "a1b2c3d4", "archive_002") if err != nil { return err } fmt.Println(archive["archive_id"]) ``` **CLI** ```bash ov session get-session-archive a1b2c3d4 archive_002 ``` **响应示例** ```json { "status": "ok", "result": { "archive_id": "archive_002", "abstract": "用户讨论了部署流程和鉴权配置。", "overview": "# Session Summary\n\n**Overview**: 用户讨论了部署流程和鉴权配置。", "messages": [ { "id": "msg_archive_1", "role": "user", "parts": [ {"type": "text", "text": "这个服务应该怎么部署?"} ], "created_at": "2026-03-24T08:55:01Z" }, { "id": "msg_archive_2", "role": "assistant", "parts": [ {"type": "text", "text": "建议先走分阶段部署,再核验鉴权链路。"} ], "created_at": "2026-03-24T08:55:18Z" } ] } } ``` **错误响应** 如果 archive 不存在、未完成,或者不属于该 session,接口返回 404: ```json { "status": "error", "error": { "code": "NOT_FOUND", "message": "Archive archive_002 not found" } } ``` --- ### delete_session() #### 1. API 实现介绍 删除会话及其所有数据,包括消息、归档历史、记忆等。删除操作不可逆。 **代码入口**: - `openviking/server/routers/sessions.py:delete_session()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.delete_session()` - Python SDK - `crates/ov_cli/src/commands/session.rs:delete_session()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 要删除的会话 ID | #### 3. 使用示例 **HTTP API** ```http DELETE /api/v1/sessions/{session_id} ``` ```bash curl -X DELETE http://localhost:1933/api/v1/sessions/a1b2c3d4 \ -H "X-API-Key: your-key" ``` **Python SDK** ```python import openviking as ov client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # 删除会话 await client.delete_session("a1b2c3d4") ``` **TypeScript SDK** ```typescript await client.deleteSession("session-id"); ``` **Go SDK** ```go if err := client.DeleteSession(ctx, "a1b2c3d4"); err != nil { return err } ``` **CLI** ```bash ov session delete a1b2c3d4 ``` **响应示例** ```json { "status": "ok", "result": { "session_id": "a1b2c3d4" }, "time": 0.1 } ``` --- ### add_message() #### 1. API 实现介绍 向会话中添加消息。支持两种模式:简单文本模式和 Parts 模式(支持文本、上下文引用、工具调用等)。 **Part 类型**: - `TextPart`: 纯文本内容 - `ContextPart`: 上下文引用,指向资源或记忆 - `ToolPart`: 工具调用和结果 **代码入口**: - `openviking/session/session.py:Session.add_message()` - 核心实现 - `openviking/server/routers/sessions.py:add_message()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.add_message()` - Python SDK - `crates/ov_cli/src/commands/session.rs:add_message()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 会话 ID | | role | str | 是 | - | 消息角色:"user" 或 "assistant" | | parts | List[Part] | 条件必填 | - | 消息部分列表(Python SDK 必填;HTTP API 可选,与 content 二选一) | | content | str | 条件必填 | - | 消息文本内容(HTTP API 简单模式,与 parts 二选一) | | created_at | str | 否 | None | 可选的 ISO 8601 时间戳,会原样保存到消息中 | | peer_id | str | 否 | None | 可选的稳定交互对象 ID | > **注意**:HTTP API 支持两种模式: > 1. **简单模式**:使用 `content` 字符串(向后兼容) > 2. **Parts 模式**:使用 `parts` 数组(完整 Part 支持) > > 如果同时提供 `content` 和 `parts`,`parts` 优先。 **Part 类型(Python SDK)** ```python from openviking.message import TextPart, ContextPart, ToolPart # 文本内容 TextPart(text="Hello, how can I help?") # 上下文引用 ContextPart( uri="viking://resources/docs/auth/", context_type="resource", # "resource"、"memory" 或 "skill" abstract="Authentication guide..." ) # 工具调用 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. 使用示例 **HTTP API** ```http POST /api/v1/sessions/{session_id}/messages ``` **简单模式(向后兼容)** ```bash # 添加用户消息 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 模式(完整 Part 支持)** ```bash # 添加带有上下文引用的助手消息 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"} ] }' # 添加带有工具调用的助手消息 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..."} ] }' ``` **Python SDK** ```python import openviking as ov from openviking.message import TextPart, ContextPart client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # 简单模式:添加用户消息 await client.add_message( session_id="a1b2c3d4", role="user", content="How do I authenticate users?" ) # Parts 模式:添加带有上下文引用的助手消息 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" ) ] ) ``` **TypeScript SDK** ```typescript await client.addMessage("session-id", { role: "user", content: "Hello" }); ``` **Go SDK** ```go 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** ```bash ov session add-message a1b2c3d4 --role user --content "How do I authenticate users?" ``` **响应示例** ```json { "status": "ok", "result": { "session_id": "a1b2c3d4", "message_count": 2 }, "time": 0.1 } ``` --- ### batch_add_messages() #### 1. API 实现介绍 向会话中批量添加多条消息。适用于需要一次性写入大量消息的场景(如历史对话导入、记忆抽取),相比逐条调用 `add_message()` 可显著提升性能。 **与 `add_message()` 的区别**: - `add_message()`:单次请求添加 1 条消息 - `batch_add_messages()`:单次请求添加多条消息(上限 100 条),减少网络往返和文件 I/O **代码入口**: - `openviking/session/session.py:Session.add_messages()` - 核心实现 - `openviking/server/routers/sessions.py:batch_add_messages()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.batch_add_messages()` - Python SDK - `crates/ov_cli/src/commands/session.rs:add_messages()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 会话 ID | | messages | List[AddMessageRequest] | 是 | - | 消息列表,每条消息格式与 `add_message()` 相同,最多 100 条 | | telemetry | bool | 否 | False | 是否附加操作遥测数据 | > **注意**:每条消息的格式与 `add_message()` 完全一致,支持 `content`(简单模式)和 `parts`(Parts 模式)。超过 100 条需分批调用。 #### 3. 使用示例 **HTTP API** ```http POST /api/v1/sessions/{session_id}/messages/batch ``` ```bash # 批量添加多条消息 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** ```python import openviking as ov client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # 批量添加消息 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** ```typescript await client.batchAddMessages("session-id", [ { role: "user", content: "Hello" }, { role: "assistant", content: "Hi" }, ]); ``` **Go SDK** ```go 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** ```bash # 向会话中批量添加消息 ov session add-messages a1b2c3d4 '[{"role":"user","content":"Hello"},{"role":"assistant","content":"Hi"}]' # ov add-memory 内部也自动使用批量接口 ov add-memory '[{"role":"user","content":"Hello"},{"role":"assistant","content":"Hi"}]' ``` **响应示例** ```json { "status": "ok", "result": { "session_id": "a1b2c3d4", "message_count": 5, "added": 3 }, "time": 0.1 } ``` --- ### used() #### 1. API 实现介绍 记录会话中实际使用的上下文和技能。调用 `commit()` 时,会根据此使用数据更新资源的 `active_count`,用于优化未来的检索排序。 **代码入口**: - `openviking/session/session.py:Session.used()` - 核心实现 - `openviking/server/routers/sessions.py:record_used()` - HTTP 路由 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 会话 ID | | contexts | List[str] | 否 | None | 实际使用的上下文 URI 列表 | | skill | Dict[str, Any] | 否 | None | 技能使用记录,包含 `uri`、`input`、`output`、`success` 字段 | #### 3. 使用示例 **HTTP API** ```http POST /api/v1/sessions/{session_id}/used ``` ```bash # 记录使用的上下文 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/"]}' # 记录使用的技能 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}}' ``` **响应示例** ```json { "status": "ok", "result": { "session_id": "a1b2c3d4", "contexts_used": 1, "skills_used": 0 }, "time": 0.1 } ``` --- ### commit() #### 1. API 实现介绍 提交会话。归档消息(Phase 1)立即完成;有消息被归档时,摘要生成和记忆提取(Phase 2)在后台异步执行。产生归档的 commit 返回 `status: "accepted"` 和 `task_id`;没有可归档内容的 no-op commit 返回 `status: "skipped"` 和 `task_id: null`。 **两阶段提交流程**: - **Phase 1(同步)**: 快照当前消息,清空 live session,创建归档目录,写入原始消息 - **Phase 2(异步)**: 生成摘要(L0/L1),提取长期记忆,更新关系和 active_count **注意事项**: - 同一 session 的多次快速连续 commit 会被接受;每次请求都会拿到独立的 `task_id` - 空 session,或所有消息都仍在 `keep_recent_count` 保留窗口内时,会同步完成并返回 `archived: false` - 后台 Phase 2 会按 archive 顺序串行推进:`archive_N+1` 会等待 `archive_N` 写出 `.done` 后再继续 - 如果更早的 archive 已失败且没有 `.done`,后续 commit 会直接返回错误,直到该失败被处理 - 如果提交的消息中包含带 `viking://resources/...` 的长期事实、评价、偏好或事件,记忆抽取会把资源保留为 markdown 链接,并写入 `MEMORY_FIELDS.resource_refs` **代码入口**: - `openviking/session/session.py:Session.commit_async()` - 核心实现 - `openviking/server/routers/sessions.py:commit_session()` - HTTP 路由 - `openviking_cli/client/base.py:BaseClient.commit_session()` - Python SDK - `crates/ov_cli/src/commands/session.rs:commit_session()` - CLI 命令 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 要提交的会话 ID | | keep_recent_count | int | 否 | 0 | 提交后保留为 live 状态的最近消息数 (保持 live, 不归档)。`0` (默认) 归档全部消息。 | #### 3. 使用示例 **HTTP API** ```http POST /api/v1/sessions/{session_id}/commit ``` ```bash # 提交会话(立即返回) curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/commit \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" # 查询任务状态 curl -X GET http://localhost:1933/api/v1/tasks/{task_id} \ -H "X-API-Key: your-key" ``` **Python SDK** ```python import openviking as ov client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # commit 立即返回 task_id,后台异步执行摘要生成和记忆提取 result = await client.commit_session("a1b2c3d4") print(f"Status: {result['status']}") print(f"Task ID: {result['task_id']}") # 查询后台任务状态 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** ```typescript console.log(await client.commitSession("session-id")); ``` **Go SDK** ```go 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** ```bash ov session commit a1b2c3d4 ``` **响应示例** ```json { "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 响应示例** ```json { "status": "ok", "result": { "session_id": "a1b2c3d4", "status": "skipped", "task_id": null, "archive_uri": null, "archived": false, "reason": "no_messages" } } ``` --- ### extract() #### 1. API 实现介绍 立即对已有会话触发一次记忆提取,不会额外创建新的 commit 任务。 **代码入口**: - `openviking/server/routers/sessions.py:extract_session()` - HTTP 路由 #### 2. 接口和参数说明 **参数** | 参数 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | session_id | str | 是 | - | 要提取记忆的会话 ID | #### 3. 使用示例 **HTTP API** ```http POST /api/v1/sessions/{session_id}/extract ``` ```bash curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/extract \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" ``` **响应示例** 该接口会直接返回本次提取产生的记忆写入结果列表。列表项的具体结构取决于该会话实际提取出了哪些记忆。 ## 会话属性 | 属性 | 类型 | 说明 | |------|------|------| | uri | str | 会话 Viking URI(`viking://user/{user_id}/sessions/{session_id}/`) | | messages | List[Message] | 会话中的当前消息 | | stats | SessionStats | 会话统计信息 | | summary | str | 压缩摘要 | | usage_records | List[Usage] | 上下文和技能使用记录 | --- ## 会话存储结构 ``` viking://user/{user_id}/sessions/{session_id}/ ├── .abstract.md # L0:会话概览 ├── .overview.md # L1:关键决策 ├── .meta.json # 元数据 ├── .relations.json # 关联上下文 ├── messages.jsonl # 当前消息 ├── tools/ # 工具执行记录 │ └── {tool_id}/ │ └── tool.json └── history/ # 归档历史 ├── archive_001/ │ ├── messages.jsonl # Phase 1 写入 │ ├── .abstract.md # Phase 2 写入(后台) │ ├── .overview.md # Phase 2 写入(后台) │ ├── .meta.json # 归档元数据 │ ├── memory_diff.json # 长记忆抽取完成时写入 │ ├── .done # Phase 2 完成标记 │ └── .failed.json # Phase 2 失败标记 └── archive_002/ ``` ### memory_diff.json 数据结构 长记忆抽取成功运行时,会在归档目录写入 `memory_diff.json`,记录所有记忆变更,便于审计和回溯: ```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": "新创建的文件内容" } ], "updates": [ { "uri": "memory/user/xxx/context/project.md", "memory_type": "context", "before": "修改前的文件内容", "after": "修改后的文件内容" } ], "deletes": [ { "uri": "memory/user/xxx/context/old.md", "memory_type": "context", "deleted_content": "被删除的文件内容" } ] }, "summary": { "total_adds": 1, "total_updates": 1, "total_deletes": 1 } } ``` | 字段 | 类型 | 说明 | |------|------|------| | `archive_uri` | str | 本次提交的归档目录 URI | | `extracted_at` | str | 提取时间的 ISO 8601 格式 | | `operations.adds` | array | 新增记忆(`uri`、`memory_type`、`after`) | | `operations.updates` | array | 修改记忆(`uri`、`memory_type`、`before`、`after`) | | `operations.deletes` | array | 删除记忆(`uri`、`memory_type`、`deleted_content`) | | `summary.total_adds` | int | 新增记忆数 | | `summary.total_updates` | int | 修改记忆数 | | `summary.total_deletes` | int | 删除记忆数 | 如果长记忆抽取已运行但没有产生记忆操作,也会写入空结构的 `memory_diff.json`(所有计数为零)。 ## 完整示例 **Python SDK** ```python import openviking as ov from openviking.message import TextPart, ContextPart # 初始化客户端 client = ov.Client(base_url="http://localhost:1933", api_key="your-key") # 创建新会话 session_result = await client.create_session() session_id = session_result["session_id"] print(f"Session created: {session_id}") # 添加用户消息 await client.add_message( session_id=session_id, role="user", content="How do I configure embedding?" ) # 使用会话上下文进行搜索 results = await client.search("embedding configuration", session_id=session_id) # 添加带有上下文引用的助手回复 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_result = await client.commit_session(session_id) print(f"Task ID: {commit_result['task_id']}") # 可选:等待后台任务完成 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** ```bash # 步骤 1:创建会话 curl -X POST http://localhost:1933/api/v1/sessions \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" # 返回:{"status": "ok", "result": {"session_id": "a1b2c3d4"}} # 步骤 2:添加用户消息 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?"}' # 步骤 3:使用会话上下文进行搜索 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"}' # 步骤 4:添加助手消息 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..."}' # 步骤 5:记录使用的上下文 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/"]}' # 步骤 6:提交会话(立即返回 task_id) curl -X POST http://localhost:1933/api/v1/sessions/a1b2c3d4/commit \ -H "Content-Type: application/json" \ -H "X-API-Key: your-key" # 返回:{"status": "ok", "result": {"status": "accepted", "task_id": "uuid-xxx", ...}} # 步骤 7:查询后台任务状态(可选) curl -X GET http://localhost:1933/api/v1/tasks/uuid-xxx \ -H "X-API-Key: your-key" ``` ## 最佳实践 ### 定期提交 ```python # 在重要交互后提交 session_info = await client.get_session(session_id) if session_info["message_count"] > 10: await client.commit_session(session_id) ``` ### 使用会话上下文进行搜索 ```python # 结合对话上下文可获得更好的搜索结果 results = await client.search(query, session_id=session_id) ``` --- ## 相关文档 - [上下文类型](../concepts/02-context-types.md) - 记忆类型 - [记忆](16-memory.md) - 记忆类型与类型配额召回 - [检索](06-retrieval.md) - 结合会话进行搜索 - [资源管理](02-resources.md) - 资源管理 - [后台任务](17-tasks.md) - 跟踪 commit 任务