@openviking/openclaw-plugin 2026.9.4 → 2026.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INSTALL-AGENT.md CHANGED
@@ -42,6 +42,7 @@ Before setup, determine:
42
42
  | --- | --- | --- |
43
43
  | OpenViking base URL | Yes | Ask user or read `OPENVIKING_BASE_URL` |
44
44
  | API key | Usually | Ask user or read `OPENVIKING_API_KEY` |
45
+ | Memory scope | Optional; default `none` | Ask whether memory is shared, separated by assistant, or separated by sender. Use `sender`; accept legacy `person` as an alias. |
45
46
  | Account ID | Only for root API keys | Ask user if setup reports root-key tenant context is needed |
46
47
  | User ID | Only for root API keys | Ask user if setup reports root-key tenant context is needed |
47
48
  | Slot replacement approval | Only if another context engine owns the slot | Ask user before using `--force-slot` |
@@ -73,6 +74,23 @@ Run setup with `--json` whenever possible:
73
74
  openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --json
74
75
  ```
75
76
 
77
+ Choose memory scope before building that command:
78
+
79
+ | Value | Concrete layout | Use when |
80
+ | --- | --- | --- |
81
+ | `none` (default; omit the flag) | Shared `viking://user/<user_id>/memories/...`; no concrete peer memory subtree | General case |
82
+ | `assistant` | Assistant-attributed peer memory under `.../peers/<assistant_id>/memories/...` | A human is the OpenViking user and uses multiple OpenClaw assistants |
83
+ | `sender` | Sender-attributed peer memory under `.../peers/<sender_id>/memories/...` | An agent is the OpenViking user and receives messages from multiple humans |
84
+
85
+ `person` is a legacy alias for `sender`. Accept it from existing config or user input, but write `sender` in new setup commands. OpenViking initializes the managed `peers/` container for every user; `none` only means that no concrete `peers/<peer_id>/memories` subtree is used. Actor-peer recall includes shared user memory plus the current peer memory, and changing the scope does not move existing memories.
86
+
87
+ Examples:
88
+
89
+ ```bash
90
+ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role assistant --json
91
+ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role sender --json
92
+ ```
93
+
76
94
  Branch on the result:
77
95
 
78
96
  | JSON result | Meaning | Agent action |
@@ -96,10 +114,10 @@ openclaw openviking setup \
96
114
  --json
97
115
  ```
98
116
 
99
- Custom agent routing prefix (optional; only when the user explicitly requests a prefix):
117
+ Custom assistant routing prefix (optional; only with `peer_role=assistant` and when the user explicitly requests a prefix):
100
118
 
101
119
  ```bash
102
- openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-prefix <PREFIX> --json
120
+ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role assistant --peer-prefix <PREFIX> --json
103
121
  ```
104
122
 
105
123
  Slot replacement retry, only after user approval:
@@ -139,6 +157,7 @@ Also inspect:
139
157
  | `health.version` | Records server version |
140
158
  | `health.compatibility` | Determines whether to warn |
141
159
  | `config.hasApiKey` | Confirms whether an API key was saved |
160
+ | `config.peer_role` | Confirms `none`, `assistant`, or canonical `sender` scope |
142
161
  | `config.peer_prefix` | Confirms configured peer prefix when present |
143
162
 
144
163
  ## Environment Detection
@@ -267,7 +286,8 @@ Core fields:
267
286
  | `mode` | Legacy compatibility field. Expected value: `remote`. |
268
287
  | `baseUrl` | OpenViking HTTP endpoint |
269
288
  | `apiKey` | OpenViking API key |
270
- | `peer_prefix` | Optional; prefix for OpenClaw agent IDs when set. Interactive setup accepts only letters, digits, `_`, and `-`. If unset, the plugin follows session agent IDs. |
289
+ | `peer_role` | `none` (shared user memory), `assistant` (`peers/<assistant_id>`), or `sender` (`peers/<sender_id>`). Legacy `person` is accepted as `sender`. |
290
+ | `peer_prefix` | Optional only with `peer_role=assistant`; prefix for OpenClaw agent IDs. Interactive setup accepts only letters, digits, `_`, and `-`. If unset, the plugin follows session agent IDs. |
271
291
  | `accountId` | Required for root API keys |
272
292
  | `userId` | Required for root API keys |
273
293
 
@@ -329,7 +349,8 @@ Existing config fields are preserved during migration. The new plugin reads old
329
349
 
330
350
  - `baseUrl`
331
351
  - `apiKey`
332
- - `peer_prefix`: optional; interactive setup accepts only letters, digits, `_`, and `-`
352
+ - `peer_role`: optional; `none`, `assistant`, or `sender`; legacy `person` is accepted as `sender`
353
+ - `peer_prefix`: optional only with `peer_role=assistant`; interactive setup accepts only letters, digits, `_`, and `-`
333
354
 
334
355
  ## Backup Path: ov-install
335
356
 
package/INSTALL-ZH.md CHANGED
@@ -197,12 +197,30 @@ openclaw openviking setup \
197
197
  openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --force-slot --json
198
198
  ```
199
199
 
200
- 如需给默认 assistant peer 路由增加前缀,可以额外传:
200
+ 根据 OpenViking user 代表谁来选择 `--peer-role`:
201
+
202
+ | 值 | 存储示例 | 适用场景 |
203
+ | --- | --- | --- |
204
+ | `none`(默认) | `viking://user/alice/memories/...` | 该 OpenViking 用户下的所有对话共享 user-level 记忆,不使用具体 peer 的记忆子树。 |
205
+ | `assistant` | `viking://user/alice/peers/main/memories/...` | OpenViking user 代表人,并希望把 assistant 归因的 peer 记忆按不同 OpenClaw 助手分开。 |
206
+ | `sender` | `viking://user/support-agent/peers/customer-42/memories/...` | OpenViking user 代表 agent,并希望把 sender 归因的 peer 记忆按不同发送者分开。 |
207
+
208
+ `person` 仍作为 `sender` 的旧配置别名被兼容;新配置请使用 `sender`。
209
+
210
+ 例如,让每个助手使用独立的 peer 记忆,并可选给 assistant id 加前缀:
201
211
 
202
212
  ```bash
203
213
  openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role assistant --peer-prefix <PREFIX> --json
204
214
  ```
205
215
 
216
+ 如果 OpenViking user 是 agent,按给它发消息的 sender 分开 peer 记忆:
217
+
218
+ ```bash
219
+ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role sender --json
220
+ ```
221
+
222
+ OpenViking 会为每个用户初始化受管的 `peers/` 容器。`none` 表示插件不创建、也不路由到具体的 `peers/<peer_id>/memories` 子树。Actor-peer 召回同时包含用户共享记忆和当前 peer 记忆;切换配置不会搬迁已有记忆。
223
+
206
224
  #### 无法执行 CLI 时直接配置文件
207
225
 
208
226
  如果容器内无法执行 `openclaw` CLI,可以把以下字段合并到 OpenClaw 实际读取的配置文件。设置了 `OPENCLAW_CONFIG_PATH` 时使用该路径;否则通常是 `$OPENCLAW_STATE_DIR/openclaw.json`(默认 `~/.openclaw/openclaw.json`)。
@@ -300,7 +318,7 @@ plugins.entries.openviking.config
300
318
  | `mode` | `remote` | 兼容旧配置的字段。当前只支持 remote。 |
301
319
  | `baseUrl` | `http://127.0.0.1:1933` | OpenViking HTTP 地址 |
302
320
  | `apiKey` | 空 | OpenViking API key |
303
- | `peer_role` | `assistant` | Peer 身份模式:`none`、`assistant` 或 `person`。Session message 使用 body `peer_id`;数据面 recall/search 使用 `X-OpenViking-Actor-Peer`。 |
321
+ | `peer_role` | `none` | 记忆归属:`none`(共享 `viking://user/<user_id>/memories`)、`assistant`(`.../peers/<assistant_id>/memories`)或 `sender`(`.../peers/<sender_id>/memories`)。旧值 `person` 作为 `sender` 的别名兼容。Session message 使用 body `peer_id`;数据面 recall/search 使用 `X-OpenViking-Actor-Peer`。 |
304
322
  | `peer_prefix` | 空 | `peer_role=assistant` 时 assistant `peer_id` / actor peer 值的可选前缀。 |
305
323
  | `accountId` | 空 | 使用 root API key 时需要 |
306
324
  | `userId` | 空 | 使用 root API key 时需要 |
@@ -325,7 +343,7 @@ openclaw config get plugins.entries.openviking.config
325
343
  | --- | --- | --- |
326
344
  | `baseUrl` | `http://127.0.0.1:1933` | 远端 OpenViking 服务地址 |
327
345
  | `apiKey` | 空 | 远端 OpenViking API Key;服务端未开启认证时可不填 |
328
- | `peer_role` | `assistant` | Peer 身份模式:`none`、`assistant` 或 `person`;session message 使用 body `peer_id`,数据面 recall/search 使用 `X-OpenViking-Actor-Peer` |
346
+ | `peer_role` | `none` | 记忆归属:`none`、`assistant` 或 `sender`;旧值 `person` 作为 `sender` 的别名兼容。Session message 使用 body `peer_id`,数据面 recall/search 使用 `X-OpenViking-Actor-Peer` |
329
347
  | `peer_prefix` | 空 | `peer_role=assistant` 时 assistant `peer_id` / actor peer 值的可选前缀 |
330
348
 
331
349
  常见设置:
@@ -387,7 +405,7 @@ ov-install
387
405
  | `--current-version` | 查看 helper 记录的当前版本 |
388
406
  | `--base-url URL` | OpenViking 服务器地址(启用非交互模式) |
389
407
  | `--api-key KEY` | OpenViking API key |
390
- | `--peer-role ROLE` | Peer role:`none`、`assistant` 或 `person` |
408
+ | `--peer-role ROLE` | 记忆归属:`none`、`assistant` 或 `sender`;旧值 `person` 作为 `sender` 的别名兼容 |
391
409
  | `--peer-prefix PREFIX` | assistant `peer_id` / actor peer 值的前缀 |
392
410
  | `--update` | 更新 helper 管理的安装 |
393
411
 
package/INSTALL.md CHANGED
@@ -141,12 +141,30 @@ If another context engine already owns the slot, setup will not replace it by de
141
141
  openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --force-slot --json
142
142
  ```
143
143
 
144
- If you want assistant messages to carry a prefixed `peer_id` and data-plane recall/search requests to use the matching actor peer view, pass a prefix explicitly:
144
+ Choose `--peer-role` from what the OpenViking user represents:
145
+
146
+ | Value | Storage example | Use when |
147
+ | --- | --- | --- |
148
+ | `none` (default) | `viking://user/alice/memories/...` | All conversations for this OpenViking user share user-level memory. No peer-specific memory subtree is used. |
149
+ | `assistant` | `viking://user/alice/peers/main/memories/...` | The OpenViking user is a human and assistant-attributed peer memory should be separated by OpenClaw assistant. |
150
+ | `sender` | `viking://user/support-agent/peers/customer-42/memories/...` | The OpenViking user is an agent and sender-attributed peer memory should be separated by human sender. |
151
+
152
+ `person` is still accepted as a legacy alias for `sender`. New configuration should use `sender`.
153
+
154
+ For example, give each assistant its own peer memory and optionally namespace the assistant id:
145
155
 
146
156
  ```bash
147
157
  openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role assistant --peer-prefix <PREFIX> --json
148
158
  ```
149
159
 
160
+ Or scope peer memory by the sender talking to an agent:
161
+
162
+ ```bash
163
+ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --peer-role sender --json
164
+ ```
165
+
166
+ OpenViking initializes the managed `peers/` container for every user. `none` means the plugin does not create or route into a concrete `peers/<peer_id>/memories` subtree. Actor-peer recall includes shared user memory plus the current peer memory, and changing the setting does not move existing memories.
167
+
150
168
  #### Configure The File Directly When The CLI Is Unavailable
151
169
 
152
170
  If the `openclaw` CLI cannot run inside the container, merge the following fields into the config file that OpenClaw actually reads. Use `OPENCLAW_CONFIG_PATH` when it is set; otherwise the file is usually `$OPENCLAW_STATE_DIR/openclaw.json` (default: `~/.openclaw/openclaw.json`).
@@ -244,7 +262,7 @@ Core fields:
244
262
  | `mode` | `remote` | Legacy compatibility field. Only remote mode is supported. |
245
263
  | `baseUrl` | `http://127.0.0.1:1933` | OpenViking HTTP endpoint |
246
264
  | `apiKey` | empty | OpenViking API key |
247
- | `peer_role` | `assistant` | Peer identity mode: `none`, `assistant`, or `person`. Session messages use body `peer_id`; data-plane recall/search uses `X-OpenViking-Actor-Peer`. |
265
+ | `peer_role` | `none` | Memory scope: `none` (shared `viking://user/<user_id>/memories`), `assistant` (`.../peers/<assistant_id>/memories`), or `sender` (`.../peers/<sender_id>/memories`). Legacy `person` is accepted as `sender`. Session messages use body `peer_id`; data-plane recall/search uses `X-OpenViking-Actor-Peer`. |
248
266
  | `peer_prefix` | empty | Optional prefix for assistant `peer_id` / actor peer values when `peer_role=assistant`. |
249
267
  | `accountId` | empty | Required when using a root API key |
250
268
  | `userId` | empty | Required when using a root API key |
@@ -311,7 +329,7 @@ Useful backup/source flags:
311
329
  | `--current-version` | Print the version tracked by the helper |
312
330
  | `--base-url URL` | OpenViking server URL (enables non-interactive mode) |
313
331
  | `--api-key KEY` | OpenViking API key |
314
- | `--peer-role ROLE` | Peer role: `none`, `assistant`, or `person` |
332
+ | `--peer-role ROLE` | Memory scope: `none`, `assistant`, or `sender`; legacy `person` is accepted as `sender` |
315
333
  | `--peer-prefix PREFIX` | Prefix for assistant `peer_id` / actor peer values |
316
334
  | `--update` | Update an existing helper-managed install |
317
335
 
@@ -356,7 +374,7 @@ The plugin connects to an existing remote OpenViking server.
356
374
  | --- | --- | --- |
357
375
  | `baseUrl` | `http://127.0.0.1:1933` | Remote OpenViking HTTP endpoint |
358
376
  | `apiKey` | empty | Optional OpenViking API key |
359
- | `peer_role` | `assistant` | Peer identity mode: `none`, `assistant`, or `person`; session messages use body `peer_id`, while data-plane recall/search uses `X-OpenViking-Actor-Peer` |
377
+ | `peer_role` | `none` | Memory scope: `none`, `assistant`, or `sender`; legacy `person` is accepted as `sender`. Session messages use body `peer_id`, while data-plane recall/search uses `X-OpenViking-Actor-Peer` |
360
378
  | `peer_prefix` | empty | Optional prefix for assistant `peer_id` / actor peer values when `peer_role=assistant` |
361
379
 
362
380
  Common settings:
package/README.md CHANGED
@@ -124,15 +124,26 @@ The main rules are:
124
124
  - reuse `sessionId` directly when it is already a UUID
125
125
  - prefer `sessionKey` when deriving a stable `ovSessionId`
126
126
  - normalize unsafe path characters, or fall back to a stable SHA-256 when needed
127
- - `peer_role=assistant` is the default and writes assistant messages with `peer_id=<sessionAgent>`; if `peer_prefix` is set, the value becomes `<peer_prefix>_<sessionAgent>`
128
- - `peer_role=none` disables peer message attribution and actor-peer routing
129
- - `peer_role=person` writes user messages with `peer_id` derived from OpenClaw sender identity; assistant messages do not get `peer_id`
130
- - data-plane recall/search/read/import/delete sends the same resolved peer identity as `X-OpenViking-Actor-Peer` when `peer_role` is `assistant` or `person`
127
+ - `peer_role=none` is the default: messages have no peer attribution and memory stays in the shared user scope, for example `viking://user/alice/memories/...`; no peer-specific memory subtree is used
128
+ - `peer_role=assistant` writes assistant messages with `peer_id=<sessionAgent>` and uses peer-scoped memory such as `viking://user/alice/peers/main/memories/...`; if `peer_prefix` is set, the peer id becomes `<peer_prefix>_<sessionAgent>`
129
+ - `peer_role=sender` writes user messages with the OpenClaw sender identity as `peer_id` and uses peer-scoped memory such as `viking://user/support-agent/peers/customer-42/memories/...`; assistant messages do not get `peer_id`
130
+ - `person` remains accepted as a legacy config alias for `sender`, but new configuration and documentation use `sender`
131
+ - data-plane recall/search/read/import/delete sends the same resolved peer identity as `X-OpenViking-Actor-Peer` when `peer_role` is `assistant` or `sender`
131
132
  - when OpenClaw does not provide a session agent, use its default agent `main` for local session and assistant peer metadata
132
133
  - only add `X-OpenViking-Account` / `X-OpenViking-User` when `accountId` / `userId` are explicitly configured
133
134
 
134
135
  This matters because OpenViking tenant identity is account/user-scoped, while OpenClaw agent identity is runtime metadata.
135
136
 
137
+ Choose the scope from what `viking://user/<user_id>` represents:
138
+
139
+ | Model | Example | Result |
140
+ | --- | --- | --- |
141
+ | General/shared (`none`) | `user_id=alice` uses any OpenClaw assistant | Shared user memory under `viking://user/alice/memories/...` |
142
+ | Human is the OpenViking user (`assistant`) | Alice uses OpenClaw assistants `main` and `research` | Assistant-scoped memories are separated under `.../peers/main/memories/...` and `.../peers/research/memories/...` |
143
+ | Agent is the OpenViking user (`sender`) | `user_id=support-agent` receives messages from `customer-42` and `customer-99` | Sender-scoped memories are separated under `.../peers/customer-42/memories/...` and `.../peers/customer-99/memories/...` |
144
+
145
+ OpenViking creates the managed `peers/` container as part of the user namespace. `none` means that the plugin does not create or route into a specific `peers/<peer_id>/memories` subtree. With `assistant` or `sender`, actor-peer recall includes the shared user memory plus the current peer's memory; changing the setting does not move existing memories.
146
+
136
147
  The recommended remote-mode configuration only needs:
137
148
 
138
149
  - `baseUrl`
@@ -143,7 +154,7 @@ The recommended remote-mode configuration only needs:
143
154
  In this setup:
144
155
 
145
156
  - `apiKey` should usually be a user key
146
- - new installs default to `peer_role=assistant`
157
+ - new installs default to `peer_role=none`
147
158
  - `accountId` / `userId` are advanced options only when the deployment needs explicit identity headers, such as root-key or trusted-server flows
148
159
 
149
160
  ### User namespace
package/commands/setup.ts CHANGED
@@ -84,8 +84,8 @@ const CONFIG_KEYS_TO_PRESERVE = [
84
84
  "logFindRequests",
85
85
  ] as const;
86
86
 
87
- type PeerRole = "none" | "assistant" | "person";
88
- const DEFAULT_SETUP_PEER_ROLE: PeerRole = "assistant";
87
+ type PeerRole = "none" | "assistant" | "sender";
88
+ const DEFAULT_SETUP_PEER_ROLE: PeerRole = "none";
89
89
  type RecallTargetType = "resource" | "user" | "agent";
90
90
  const ALLOWED_RECALL_TARGET_TYPES = ["resource", "user", "agent"] as const;
91
91
 
@@ -126,7 +126,8 @@ function isValidPeerPrefixInput(value: string): boolean {
126
126
  function normalizePeerRole(value: unknown): PeerRole | undefined {
127
127
  if (typeof value !== "string") return undefined;
128
128
  const role = value.trim().toLowerCase();
129
- if (role === "none" || role === "assistant" || role === "person") return role;
129
+ if (role === "person") return "sender";
130
+ if (role === "none" || role === "assistant" || role === "sender") return role;
130
131
  return undefined;
131
132
  }
132
133
 
@@ -147,7 +148,7 @@ function resolveSetupPeerRole(value: unknown): PeerRole {
147
148
  if (value === undefined) return DEFAULT_SETUP_PEER_ROLE;
148
149
  const role = normalizePeerRole(value);
149
150
  if (role) return role;
150
- throw new Error('peer_role must be "none", "assistant", or "person"');
151
+ throw new Error('peer_role must be "none", "assistant", or "sender" (legacy alias: "person")');
151
152
  }
152
153
 
153
154
  function normalizeSetupRecallTargetTypes(value: unknown): RecallTargetType[] | undefined {
@@ -206,9 +207,20 @@ async function askPeerRole(
206
207
  q: (prompt: string, def?: string) => Promise<string>,
207
208
  defaultValue: PeerRole,
208
209
  ): Promise<PeerRole> {
210
+ console.log(
211
+ ` ${tr(
212
+ zh,
213
+ "Memory scope — none (default): viking://user/<user_id>/memories, shared across all conversations; " +
214
+ "assistant: viking://user/<user_id>/peers/<assistant_id>/memories; " +
215
+ "sender: viking://user/<user_id>/peers/<sender_id>/memories (legacy alias: person).",
216
+ "记忆归属 —— none(默认):viking://user/<user_id>/memories,所有对话共享;" +
217
+ "assistant:viking://user/<user_id>/peers/<assistant_id>/memories;" +
218
+ "sender:viking://user/<user_id>/peers/<sender_id>/memories(兼容旧值 person)。",
219
+ )}`,
220
+ );
209
221
  while (true) {
210
222
  const value = await q(
211
- tr(zh, "Peer Role (none/assistant/person)", "Peer Role(none/assistant/person)"),
223
+ tr(zh, "Memory scope (none/assistant/sender)", "记忆归属(none/assistant/sender)"),
212
224
  defaultValue,
213
225
  );
214
226
  const role = normalizePeerRole(value);
@@ -216,8 +228,8 @@ async function askPeerRole(
216
228
  console.log(
217
229
  ` ✗ ${tr(
218
230
  zh,
219
- 'Peer Role must be "none", "assistant", or "person".',
220
- 'Peer Role 必须是 "none"、"assistant" 或 "person"。',
231
+ 'Memory scope must be "none", "assistant", or "sender" (legacy "person" is also accepted).',
232
+ '记忆归属必须是 "none"、"assistant" 或 "sender"(也兼容旧值 "person")。',
221
233
  )}`,
222
234
  );
223
235
  }
@@ -605,7 +617,7 @@ export function registerSetupCli(api: any): void {
605
617
  .option("--zh", "Chinese prompts")
606
618
  .option("--base-url <url>", "OpenViking server URL (enables non-interactive mode)")
607
619
  .option("--api-key <key>", "API key for authentication")
608
- .option("--peer-role <role>", "Peer ID role: none, assistant, or person")
620
+ .option("--peer-role <role>", "Memory scope: none (shared), assistant (per assistant), or sender (per sender); person is a legacy alias")
609
621
  .option("--peer-prefix <prefix>", "Prefix for assistant peer_id values")
610
622
  .option("--account-id <id>", "Account ID (required for root API keys)")
611
623
  .option("--user-id <id>", "User ID (required for root API keys)")
@@ -1182,6 +1194,8 @@ async function setupRemote(
1182
1194
  export const __test__ = {
1183
1195
  isLegacyLocalMode,
1184
1196
  isValidPeerPrefixInput,
1197
+ normalizePeerRole,
1198
+ resolveSetupPeerRole,
1185
1199
  normalizeSetupRecallTargetTypes,
1186
1200
  activateContextEngineSlot,
1187
1201
  isContextEngineSlotActive,
package/config.ts CHANGED
@@ -30,7 +30,8 @@ export type OpenVikingSecretRef =
30
30
  export type MemoryOpenVikingConfig = {
31
31
  mode?: "remote";
32
32
  baseUrl?: string;
33
- peer_role?: "none" | "assistant" | "person";
33
+ /** `person` is a legacy alias for `sender`. */
34
+ peer_role?: "none" | "assistant" | "sender" | "person";
34
35
  peer_prefix?: string;
35
36
  apiKey?: string | OpenVikingSecretRef;
36
37
  /** Optional HTTP headers merged into every OpenViking request. */
@@ -127,10 +128,12 @@ export type MemoryOpenVikingConfig = {
127
128
 
128
129
  /** Runtime config after memoryOpenVikingConfigSchema.parse() has applied defaults. */
129
130
  export type ParsedMemoryOpenVikingConfig = Required<
130
- Omit<MemoryOpenVikingConfig, "agentExperience" | "recallTargetTypes" | "apiKey">
131
+ Omit<MemoryOpenVikingConfig, "agentExperience" | "recallTargetTypes" | "apiKey" | "peer_role">
131
132
  > & {
132
133
  /** parse() resolves SecretRef values, so the runtime shape is always a plain string. */
133
134
  apiKey: string;
135
+ /** Runtime uses the canonical name; legacy `person` input normalizes to `sender`. */
136
+ peer_role: "none" | "assistant" | "sender";
134
137
  agentExperience: Required<NonNullable<MemoryOpenVikingConfig["agentExperience"]>>;
135
138
  recallTargetTypes: Array<"resource" | "user" | "agent">;
136
139
  };
@@ -152,7 +155,7 @@ const DEFAULT_COMMIT_TOKEN_THRESHOLD_RATIO = 0.5;
152
155
  const DEFAULT_COMMIT_KEEP_RECENT_COUNT = 10;
153
156
  const DEFAULT_BYPASS_SESSION_PATTERNS: string[] = [];
154
157
  const DEFAULT_EMIT_STANDARD_DIAGNOSTICS = false;
155
- const DEFAULT_PEER_ROLE = "assistant" as const;
158
+ const DEFAULT_PEER_ROLE = "none" as const;
156
159
  const DEFAULT_PEER_PREFIX = "";
157
160
  const DEFAULT_TRACE_RECALL_DIR = "~/.openclaw/openviking/recall-traces";
158
161
  const DEFAULT_TRACE_RECALL_RETENTION_DAYS = 14;
@@ -292,16 +295,23 @@ function resolveSecret(
292
295
  }
293
296
  }
294
297
 
295
- function resolvePeerRole(configured: unknown) {
298
+ function resolvePeerRole(configured: unknown): "none" | "assistant" | "sender" {
296
299
  if (typeof configured === "string") {
297
300
  const role = configured.trim().toLowerCase();
298
- if (role === "none" || role === "assistant" || role === "person") {
301
+ if (role === "none" || role === "assistant" || role === "sender") {
299
302
  return role;
300
303
  }
301
- throw new Error(`openviking peer_role must be "none", "assistant", or "person"`);
304
+ if (role === "person") {
305
+ return "sender";
306
+ }
307
+ throw new Error(
308
+ `openviking peer_role must be "none", "assistant", or "sender" (legacy alias: "person")`,
309
+ );
302
310
  }
303
311
  if (configured !== undefined) {
304
- throw new Error(`openviking peer_role must be "none", "assistant", or "person"`);
312
+ throw new Error(
313
+ `openviking peer_role must be "none", "assistant", or "sender" (legacy alias: "person")`,
314
+ );
305
315
  }
306
316
  return DEFAULT_PEER_ROLE;
307
317
  }
@@ -776,14 +786,17 @@ export const memoryOpenVikingConfigSchema = {
776
786
  help: "HTTP URL when mode is remote (or use ${OPENVIKING_BASE_URL})",
777
787
  },
778
788
  peer_role: {
779
- label: "Peer Role",
789
+ label: "Memory Scope (peer_role)",
780
790
  placeholder: DEFAULT_PEER_ROLE,
781
- help: 'Controls which session messages get peer_id: "none", "assistant", or "person".',
791
+ help:
792
+ 'Where peer-scoped memories are stored. "none" (default): viking://user/<user_id>/memories. ' +
793
+ '"assistant": viking://user/<user_id>/peers/<assistant_id>/memories. ' +
794
+ '"sender": viking://user/<user_id>/peers/<sender_id>/memories. Legacy "person" is accepted as "sender".',
782
795
  },
783
796
  peer_prefix: {
784
797
  label: "Peer Prefix",
785
798
  placeholder: "optional-prefix",
786
- help: "Optional prefix applied to assistant peer_id values derived from OpenClaw runtime agent IDs.",
799
+ help: 'Only used when Memory Scope is "assistant". Prefix added to the peer id derived from the OpenClaw agent id.',
787
800
  },
788
801
  apiKey: {
789
802
  label: "OpenViking API Key",
@@ -894,7 +907,7 @@ export const memoryOpenVikingConfigSchema = {
894
907
  bypassSessionPatterns: {
895
908
  label: "Bypass Session Patterns",
896
909
  placeholder: "agent:*:cron:**",
897
- help: "Completely bypass OpenViking for matching session keys. Use * within one segment and ** across segments.",
910
+ help: "Completely bypass OpenViking for matching session keys (no capture, recall, or commit; compaction falls back to OpenClaw's native compactor). Use * within one segment and ** across segments.",
898
911
  advanced: true,
899
912
  },
900
913
  commitTokenThresholdRatio: {
package/context-engine.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { OpenVikingClient } from "./client.js";
2
- import type { MemoryOpenVikingConfig } from "./config.js";
2
+ import type { ParsedMemoryOpenVikingConfig } from "./config.js";
3
3
  import type { RuntimeQueryConfigStore } from "./query-config.js";
4
4
  import {
5
5
  AUTO_RECALL_SOURCE_MARKER,
@@ -19,6 +19,7 @@ import {
19
19
  compactOpenVikingSession,
20
20
  commitOpenVikingSession,
21
21
  } from "./services/context-lifecycle-service.js";
22
+ import { loadRuntimeCompactionDelegate } from "./plugin/openclaw-runtime-compaction.js";
22
23
 
23
24
  type ContextEngineInfo = {
24
25
  id: string;
@@ -248,7 +249,7 @@ export function createMemoryOpenVikingContextEngine(params: {
248
249
  id: string;
249
250
  name: string;
250
251
  version?: string;
251
- cfg: Required<MemoryOpenVikingConfig>;
252
+ cfg: ParsedMemoryOpenVikingConfig;
252
253
  logger: Logger;
253
254
  getClient: () => Promise<OpenVikingClient>;
254
255
  /** Extra args help match hook-populated routing when OpenClaw provides sessionKey / OV session id. */
@@ -437,6 +438,10 @@ export function createMemoryOpenVikingContextEngine(params: {
437
438
  logger,
438
439
  resolveAgentId,
439
440
  isBypassedSession,
441
+ runtimeCompact: async () => {
442
+ const delegate = await loadRuntimeCompactionDelegate();
443
+ return delegate ? delegate(compactParams) : undefined;
444
+ },
440
445
  diag,
441
446
  });
442
447
  },
@@ -76,7 +76,7 @@ const CONFIG_KEYS_TO_PRESERVE = [
76
76
  "emitStandardDiagnostics",
77
77
  "logFindRequests",
78
78
  ];
79
- const DEFAULT_SETUP_PEER_ROLE = "assistant";
79
+ const DEFAULT_SETUP_PEER_ROLE = "none";
80
80
  const ALLOWED_RECALL_TARGET_TYPES = ["resource", "user", "agent"];
81
81
  function tr(langZh, en, zh) {
82
82
  return langZh ? zh : en;
@@ -98,7 +98,9 @@ function normalizePeerRole(value) {
98
98
  if (typeof value !== "string")
99
99
  return undefined;
100
100
  const role = value.trim().toLowerCase();
101
- if (role === "none" || role === "assistant" || role === "person")
101
+ if (role === "person")
102
+ return "sender";
103
+ if (role === "none" || role === "assistant" || role === "sender")
102
104
  return role;
103
105
  return undefined;
104
106
  }
@@ -121,7 +123,7 @@ function resolveSetupPeerRole(value) {
121
123
  const role = normalizePeerRole(value);
122
124
  if (role)
123
125
  return role;
124
- throw new Error('peer_role must be "none", "assistant", or "person"');
126
+ throw new Error('peer_role must be "none", "assistant", or "sender" (legacy alias: "person")');
125
127
  }
126
128
  function normalizeSetupRecallTargetTypes(value) {
127
129
  if (value === undefined || value === null || value === "") {
@@ -172,12 +174,17 @@ function preserveCurrentConfig(existing) {
172
174
  return config;
173
175
  }
174
176
  async function askPeerRole(zh, q, defaultValue) {
177
+ console.log(` ${tr(zh, "Memory scope — none (default): viking://user/<user_id>/memories, shared across all conversations; " +
178
+ "assistant: viking://user/<user_id>/peers/<assistant_id>/memories; " +
179
+ "sender: viking://user/<user_id>/peers/<sender_id>/memories (legacy alias: person).", "记忆归属 —— none(默认):viking://user/<user_id>/memories,所有对话共享;" +
180
+ "assistant:viking://user/<user_id>/peers/<assistant_id>/memories;" +
181
+ "sender:viking://user/<user_id>/peers/<sender_id>/memories(兼容旧值 person)。")}`);
175
182
  while (true) {
176
- const value = await q(tr(zh, "Peer Role (none/assistant/person)", "Peer Role(none/assistant/person)"), defaultValue);
183
+ const value = await q(tr(zh, "Memory scope (none/assistant/sender)", "记忆归属(none/assistant/sender)"), defaultValue);
177
184
  const role = normalizePeerRole(value);
178
185
  if (role)
179
186
  return role;
180
- console.log(` ✗ ${tr(zh, 'Peer Role must be "none", "assistant", or "person".', 'Peer Role 必须是 "none"、"assistant" 或 "person"。')}`);
187
+ console.log(` ✗ ${tr(zh, 'Memory scope must be "none", "assistant", or "sender" (legacy "person" is also accepted).', '记忆归属必须是 "none"、"assistant" 或 "sender"(也兼容旧值 "person")。')}`);
181
188
  }
182
189
  }
183
190
  async function askPeerPrefix(zh, q, defaultValue) {
@@ -473,7 +480,7 @@ export function registerSetupCli(api) {
473
480
  .option("--zh", "Chinese prompts")
474
481
  .option("--base-url <url>", "OpenViking server URL (enables non-interactive mode)")
475
482
  .option("--api-key <key>", "API key for authentication")
476
- .option("--peer-role <role>", "Peer ID role: none, assistant, or person")
483
+ .option("--peer-role <role>", "Memory scope: none (shared), assistant (per assistant), or sender (per sender); person is a legacy alias")
477
484
  .option("--peer-prefix <prefix>", "Prefix for assistant peer_id values")
478
485
  .option("--account-id <id>", "Account ID (required for root API keys)")
479
486
  .option("--user-id <id>", "User ID (required for root API keys)")
@@ -952,6 +959,8 @@ async function setupRemote(zh, configPath, existing, q) {
952
959
  export const __test__ = {
953
960
  isLegacyLocalMode,
954
961
  isValidPeerPrefixInput,
962
+ normalizePeerRole,
963
+ resolveSetupPeerRole,
955
964
  normalizeSetupRecallTargetTypes,
956
965
  activateContextEngineSlot,
957
966
  isContextEngineSlotActive,
package/dist/config.js CHANGED
@@ -18,7 +18,7 @@ const DEFAULT_COMMIT_TOKEN_THRESHOLD_RATIO = 0.5;
18
18
  const DEFAULT_COMMIT_KEEP_RECENT_COUNT = 10;
19
19
  const DEFAULT_BYPASS_SESSION_PATTERNS = [];
20
20
  const DEFAULT_EMIT_STANDARD_DIAGNOSTICS = false;
21
- const DEFAULT_PEER_ROLE = "assistant";
21
+ const DEFAULT_PEER_ROLE = "none";
22
22
  const DEFAULT_PEER_PREFIX = "";
23
23
  const DEFAULT_TRACE_RECALL_DIR = "~/.openclaw/openviking/recall-traces";
24
24
  const DEFAULT_TRACE_RECALL_RETENTION_DAYS = 14;
@@ -144,13 +144,16 @@ function resolveSecret(value, label) {
144
144
  function resolvePeerRole(configured) {
145
145
  if (typeof configured === "string") {
146
146
  const role = configured.trim().toLowerCase();
147
- if (role === "none" || role === "assistant" || role === "person") {
147
+ if (role === "none" || role === "assistant" || role === "sender") {
148
148
  return role;
149
149
  }
150
- throw new Error(`openviking peer_role must be "none", "assistant", or "person"`);
150
+ if (role === "person") {
151
+ return "sender";
152
+ }
153
+ throw new Error(`openviking peer_role must be "none", "assistant", or "sender" (legacy alias: "person")`);
151
154
  }
152
155
  if (configured !== undefined) {
153
- throw new Error(`openviking peer_role must be "none", "assistant", or "person"`);
156
+ throw new Error(`openviking peer_role must be "none", "assistant", or "sender" (legacy alias: "person")`);
154
157
  }
155
158
  return DEFAULT_PEER_ROLE;
156
159
  }
@@ -481,14 +484,16 @@ export const memoryOpenVikingConfigSchema = {
481
484
  help: "HTTP URL when mode is remote (or use ${OPENVIKING_BASE_URL})",
482
485
  },
483
486
  peer_role: {
484
- label: "Peer Role",
487
+ label: "Memory Scope (peer_role)",
485
488
  placeholder: DEFAULT_PEER_ROLE,
486
- help: 'Controls which session messages get peer_id: "none", "assistant", or "person".',
489
+ help: 'Where peer-scoped memories are stored. "none" (default): viking://user/<user_id>/memories. ' +
490
+ '"assistant": viking://user/<user_id>/peers/<assistant_id>/memories. ' +
491
+ '"sender": viking://user/<user_id>/peers/<sender_id>/memories. Legacy "person" is accepted as "sender".',
487
492
  },
488
493
  peer_prefix: {
489
494
  label: "Peer Prefix",
490
495
  placeholder: "optional-prefix",
491
- help: "Optional prefix applied to assistant peer_id values derived from OpenClaw runtime agent IDs.",
496
+ help: 'Only used when Memory Scope is "assistant". Prefix added to the peer id derived from the OpenClaw agent id.',
492
497
  },
493
498
  apiKey: {
494
499
  label: "OpenViking API Key",
@@ -598,7 +603,7 @@ export const memoryOpenVikingConfigSchema = {
598
603
  bypassSessionPatterns: {
599
604
  label: "Bypass Session Patterns",
600
605
  placeholder: "agent:*:cron:**",
601
- help: "Completely bypass OpenViking for matching session keys. Use * within one segment and ** across segments.",
606
+ help: "Completely bypass OpenViking for matching session keys (no capture, recall, or commit; compaction falls back to OpenClaw's native compactor). Use * within one segment and ** across segments.",
602
607
  advanced: true,
603
608
  },
604
609
  commitTokenThresholdRatio: {
@@ -3,6 +3,7 @@ import { compileSessionPatterns, shouldBypassSession, } from "./text-utils.js";
3
3
  import { estimateAgentMessageTokens, estimateAgentMessagesTokens } from "./token-estimator.js";
4
4
  import { openClawSessionToOvStorageId } from "./routing/identity-routing.js";
5
5
  import { assembleOpenVikingSession, afterTurnOpenVikingSession, compactOpenVikingSession, commitOpenVikingSession, } from "./services/context-lifecycle-service.js";
6
+ import { loadRuntimeCompactionDelegate } from "./plugin/openclaw-runtime-compaction.js";
6
7
  function roughEstimate(messages) {
7
8
  return estimateAgentMessagesTokens(messages);
8
9
  }
@@ -255,6 +256,10 @@ export function createMemoryOpenVikingContextEngine(params) {
255
256
  logger,
256
257
  resolveAgentId,
257
258
  isBypassedSession,
259
+ runtimeCompact: async () => {
260
+ const delegate = await loadRuntimeCompactionDelegate();
261
+ return delegate ? delegate(compactParams) : undefined;
262
+ },
258
263
  diag,
259
264
  });
260
265
  },
@@ -0,0 +1,20 @@
1
+ // Bridge to OpenClaw's built-in compactor for sessions that bypass OpenViking.
2
+ // The host exports `delegateCompactionToRuntime` from `openclaw/plugin-sdk/core`
3
+ // (present since the earliest supported host); it is resolved lazily because the
4
+ // plugin builds without the host SDK installed.
5
+ const PLUGIN_SDK_CORE_SPECIFIER = "openclaw/plugin-sdk/core";
6
+ let cached;
7
+ export function loadRuntimeCompactionDelegate() {
8
+ cached ??= (async () => {
9
+ try {
10
+ const mod = (await import(PLUGIN_SDK_CORE_SPECIFIER));
11
+ return typeof mod?.delegateCompactionToRuntime === "function"
12
+ ? mod.delegateCompactionToRuntime
13
+ : undefined;
14
+ }
15
+ catch {
16
+ return undefined;
17
+ }
18
+ })();
19
+ return cached;
20
+ }
@@ -45,7 +45,7 @@ export function registerOpenVikingMemoryTools(deps) {
45
45
  const peerId = resolveOpenVikingMessagePeerId({
46
46
  peerRole: deps.peerRole,
47
47
  role,
48
- personPeerId: session.actorPeerId,
48
+ senderPeerId: session.actorPeerId,
49
49
  assistantPeerId: session.actorPeerId,
50
50
  });
51
51
  await client.addSessionMessage(sessionId, role, [{ type: "text", text }], undefined, undefined, peerId);
@@ -1,6 +1,6 @@
1
1
  import { createSessionAgentResolver, openClawSessionToOvStorageId, resolveOpenVikingActorPeerId, sanitizeOpenVikingPeerId, } from "../routing/identity-routing.js";
2
2
  export function createOpenVikingSessionRoutingRuntime(options) {
3
- const peerRole = options.peerRole ?? "assistant";
3
+ const peerRole = options.peerRole ?? "none";
4
4
  const sessionAgentResolver = createSessionAgentResolver(options.peerPrefix);
5
5
  const rememberSessionAgentId = (ctx) => {
6
6
  sessionAgentResolver.remember(ctx);
@@ -48,7 +48,7 @@ export function createOpenVikingSessionRoutingRuntime(options) {
48
48
  agentId,
49
49
  actorPeerId: resolveOpenVikingActorPeerId({
50
50
  peerRole,
51
- personPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
51
+ senderPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
52
52
  assistantPeerId: agentId,
53
53
  }),
54
54
  };
@@ -12,8 +12,8 @@ export function sanitizeOpenVikingPeerId(raw) {
12
12
  return normalized || undefined;
13
13
  }
14
14
  export function resolveOpenVikingMessagePeerId(params) {
15
- if (params.peerRole === "person" && params.role === "user") {
16
- return params.personPeerId;
15
+ if (params.peerRole === "sender" && params.role === "user") {
16
+ return params.senderPeerId;
17
17
  }
18
18
  if (params.peerRole === "assistant" && params.role === "assistant") {
19
19
  return params.assistantPeerId;
@@ -23,10 +23,10 @@ export function resolveOpenVikingMessagePeerId(params) {
23
23
  export function resolveOpenVikingActorPeerId(params) {
24
24
  const actorPeerId = resolveOpenVikingMessagePeerId({
25
25
  ...params,
26
- role: params.peerRole === "person" ? "user" : "assistant",
26
+ role: params.peerRole === "sender" ? "user" : "assistant",
27
27
  });
28
- if (params.peerRole === "person" && !actorPeerId) {
29
- throw new Error("openviking: peer_role=person requires a sender identity");
28
+ if (params.peerRole === "sender" && !actorPeerId) {
29
+ throw new Error("openviking: peer_role=sender requires a sender identity");
30
30
  }
31
31
  return actorPeerId;
32
32
  }
@@ -243,8 +243,8 @@ export async function assembleOpenVikingSession({ sessionId, sessionKey, message
243
243
  const routingRef = sessionId ?? sessionKey ?? ovSessionId;
244
244
  const agentId = resolveAgentId(routingRef, sessionKey, ovSessionId);
245
245
  const actorPeerId = resolveOpenVikingActorPeerId({
246
- peerRole: cfg.peer_role ?? "assistant",
247
- personPeerId: sanitizeOpenVikingPeerId(sender.senderId),
246
+ peerRole: cfg.peer_role ?? "none",
247
+ senderPeerId: sanitizeOpenVikingPeerId(sender.senderId),
248
248
  assistantPeerId: agentId,
249
249
  });
250
250
  const queryConfig = await queryConfigStore?.getEffective({
@@ -595,9 +595,9 @@ export async function afterTurnOpenVikingSession({ sessionId, sessionKey, messag
595
595
  });
596
596
  if (ovParts.length > 0) {
597
597
  await client.addSessionMessage(ovSessionId, msg.role, ovParts, undefined, createdAt, resolveOpenVikingMessagePeerId({
598
- peerRole: cfg.peer_role ?? "assistant",
598
+ peerRole: cfg.peer_role ?? "none",
599
599
  role: msg.role,
600
- personPeerId: senderRoleId,
600
+ senderPeerId: senderRoleId,
601
601
  assistantPeerId: agentId,
602
602
  }));
603
603
  }
@@ -671,7 +671,7 @@ function compactFailureResult(reason, tokensBefore, details) {
671
671
  },
672
672
  };
673
673
  }
674
- export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBudget, currentTokenCount, force, compactionTarget, customInstructions, getClient, logger, resolveAgentId, isBypassedSession, diag, }) {
674
+ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBudget, currentTokenCount, force, compactionTarget, customInstructions, getClient, logger, resolveAgentId, isBypassedSession, runtimeCompact, diag, }) {
675
675
  const ovSessionId = openClawSessionToOvStorageId(sessionId, sessionKey);
676
676
  diag("compact_entry", ovSessionId, {
677
677
  tokenBudget,
@@ -682,6 +682,18 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
682
682
  customInstructions.trim().length > 0,
683
683
  });
684
684
  if (isBypassedSession({ sessionId, sessionKey })) {
685
+ // Bypassed sessions store nothing in OV, but the host still needs a real
686
+ // compaction (preflight hard-fails on an unknown skip reason), so hand the
687
+ // request to OpenClaw's native compactor.
688
+ const delegated = await runtimeCompact?.();
689
+ if (delegated) {
690
+ diag("compact_result", ovSessionId, {
691
+ ok: delegated.ok,
692
+ compacted: delegated.compacted,
693
+ reason: delegated.reason ?? "session_bypassed_runtime_compaction",
694
+ });
695
+ return delegated;
696
+ }
685
697
  diag("compact_result", ovSessionId, {
686
698
  ok: true,
687
699
  compacted: false,
@@ -80,14 +80,14 @@
80
80
  "help": "HTTP URL when mode is remote (or ${OPENVIKING_BASE_URL})"
81
81
  },
82
82
  "peer_role": {
83
- "label": "Peer Role",
84
- "placeholder": "assistant",
85
- "help": "Controls which messages include peer_id: none, assistant, or person. New installs default to assistant."
83
+ "label": "Memory Scope (peer_role)",
84
+ "placeholder": "none",
85
+ "help": "Where peer-scoped memories are stored. none (default): viking://user/<user_id>/memories. assistant: viking://user/<user_id>/peers/<assistant_id>/memories. sender: viking://user/<user_id>/peers/<sender_id>/memories. Legacy person is accepted as sender."
86
86
  },
87
87
  "peer_prefix": {
88
88
  "label": "Peer Prefix",
89
89
  "placeholder": "optional-prefix",
90
- "help": "Optional prefix for assistant peer_id values derived from OpenClaw runtime agent IDs."
90
+ "help": "Only used when Memory Scope is assistant. Prefix added to the peer id derived from the OpenClaw agent id."
91
91
  },
92
92
  "apiKey": {
93
93
  "label": "OpenViking API Key",
@@ -195,7 +195,7 @@
195
195
  "bypassSessionPatterns": {
196
196
  "label": "Bypass Session Patterns",
197
197
  "placeholder": "agent:*:cron:**",
198
- "help": "Completely bypass OpenViking for matching session keys. Use * within one segment and ** across segments.",
198
+ "help": "Completely bypass OpenViking for matching session keys (no capture, recall, or commit; compaction falls back to OpenClaw's native compactor). Use * within one segment and ** across segments.",
199
199
  "advanced": true
200
200
  },
201
201
  "commitTokenThresholdRatio": {
@@ -279,10 +279,11 @@
279
279
  "enum": [
280
280
  "none",
281
281
  "assistant",
282
+ "sender",
282
283
  "person"
283
284
  ],
284
- "default": "assistant",
285
- "description": "Controls which session messages include peer_id."
285
+ "default": "none",
286
+ "description": "Memory scope. none: shared user memory. assistant: peer memory keyed by OpenClaw assistant id. sender: peer memory keyed by sender id. person is a legacy alias for sender. Also controls which session messages include peer_id."
286
287
  },
287
288
  "peer_prefix": {
288
289
  "type": "string",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/openclaw-plugin",
3
- "version": "2026.9.4",
3
+ "version": "2026.9.5",
4
4
  "displayName": "OpenViking",
5
5
  "description": "OpenClaw context-engine plugin — OpenViking AI memory, long-term memory, knowledge base, semantic search, RAG, context engine. 长期记忆 · 知识库 · 语义检索 · 上下文引擎",
6
6
  "type": "module",
@@ -77,11 +77,5 @@
77
77
  "openclawVersion": "2026.5.27",
78
78
  "pluginSdkVersion": "2026.5.27"
79
79
  }
80
- },
81
- "devDependencies": {
82
- "@types/node": "^25.3.5",
83
- "@volcengine/tos-sdk": "^2.9.1",
84
- "typescript": "^5.8.0",
85
- "vitest": "^4.1.0"
86
80
  }
87
81
  }
@@ -0,0 +1,41 @@
1
+ // Bridge to OpenClaw's built-in compactor for sessions that bypass OpenViking.
2
+ // The host exports `delegateCompactionToRuntime` from `openclaw/plugin-sdk/core`
3
+ // (present since the earliest supported host); it is resolved lazily because the
4
+ // plugin builds without the host SDK installed.
5
+
6
+ export type RuntimeCompactionResult = {
7
+ ok: boolean;
8
+ compacted: boolean;
9
+ reason?: string;
10
+ result?: {
11
+ summary?: string;
12
+ firstKeptEntryId?: string;
13
+ tokensBefore: number;
14
+ tokensAfter?: number;
15
+ details?: unknown;
16
+ };
17
+ };
18
+
19
+ export type RuntimeCompactionDelegate = (
20
+ params: Record<string, unknown>,
21
+ ) => Promise<RuntimeCompactionResult>;
22
+
23
+ const PLUGIN_SDK_CORE_SPECIFIER = "openclaw/plugin-sdk/core";
24
+
25
+ let cached: Promise<RuntimeCompactionDelegate | undefined> | undefined;
26
+
27
+ export function loadRuntimeCompactionDelegate(): Promise<RuntimeCompactionDelegate | undefined> {
28
+ cached ??= (async () => {
29
+ try {
30
+ const mod = (await import(PLUGIN_SDK_CORE_SPECIFIER)) as {
31
+ delegateCompactionToRuntime?: unknown;
32
+ };
33
+ return typeof mod?.delegateCompactionToRuntime === "function"
34
+ ? (mod.delegateCompactionToRuntime as RuntimeCompactionDelegate)
35
+ : undefined;
36
+ } catch {
37
+ return undefined;
38
+ }
39
+ })();
40
+ return cached;
41
+ }
@@ -9,7 +9,7 @@ type Logger = {
9
9
  type ClientRuntimeConfig = {
10
10
  baseUrl: string;
11
11
  apiKey: string;
12
- peer_role: "none" | "assistant" | "person";
12
+ peer_role: "none" | "assistant" | "sender";
13
13
  peer_prefix: string;
14
14
  timeoutMs: number;
15
15
  accountId?: string;
@@ -114,7 +114,7 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
114
114
  const peerId = resolveOpenVikingMessagePeerId({
115
115
  peerRole: deps.peerRole,
116
116
  role,
117
- personPeerId: session.actorPeerId,
117
+ senderPeerId: session.actorPeerId,
118
118
  assistantPeerId: session.actorPeerId,
119
119
  });
120
120
  await client.addSessionMessage(
@@ -34,7 +34,7 @@ export function createOpenVikingSessionRoutingRuntime(options: {
34
34
  logFindRequests: boolean;
35
35
  logger: Logger;
36
36
  }) {
37
- const peerRole = options.peerRole ?? "assistant";
37
+ const peerRole = options.peerRole ?? "none";
38
38
  const sessionAgentResolver = createSessionAgentResolver(options.peerPrefix);
39
39
 
40
40
  const rememberSessionAgentId = (ctx: SessionAgentLookup) => {
@@ -97,7 +97,7 @@ export function createOpenVikingSessionRoutingRuntime(options: {
97
97
  agentId,
98
98
  actorPeerId: resolveOpenVikingActorPeerId({
99
99
  peerRole,
100
- personPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
100
+ senderPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
101
101
  assistantPeerId: agentId,
102
102
  }),
103
103
  };
@@ -15,7 +15,7 @@ export type SessionAgentLookup = {
15
15
  ovSessionId?: string;
16
16
  };
17
17
 
18
- export type OpenVikingPeerRole = "none" | "assistant" | "person";
18
+ export type OpenVikingPeerRole = "none" | "assistant" | "sender";
19
19
 
20
20
  export function sanitizeOpenVikingPeerId(raw?: string): string | undefined {
21
21
  const normalized = raw
@@ -29,11 +29,11 @@ export function sanitizeOpenVikingPeerId(raw?: string): string | undefined {
29
29
  export function resolveOpenVikingMessagePeerId(params: {
30
30
  peerRole: OpenVikingPeerRole;
31
31
  role?: string;
32
- personPeerId?: string;
32
+ senderPeerId?: string;
33
33
  assistantPeerId?: string;
34
34
  }): string | undefined {
35
- if (params.peerRole === "person" && params.role === "user") {
36
- return params.personPeerId;
35
+ if (params.peerRole === "sender" && params.role === "user") {
36
+ return params.senderPeerId;
37
37
  }
38
38
  if (params.peerRole === "assistant" && params.role === "assistant") {
39
39
  return params.assistantPeerId;
@@ -43,15 +43,15 @@ export function resolveOpenVikingMessagePeerId(params: {
43
43
 
44
44
  export function resolveOpenVikingActorPeerId(params: {
45
45
  peerRole: OpenVikingPeerRole;
46
- personPeerId?: string;
46
+ senderPeerId?: string;
47
47
  assistantPeerId?: string;
48
48
  }): string | undefined {
49
49
  const actorPeerId = resolveOpenVikingMessagePeerId({
50
50
  ...params,
51
- role: params.peerRole === "person" ? "user" : "assistant",
51
+ role: params.peerRole === "sender" ? "user" : "assistant",
52
52
  });
53
- if (params.peerRole === "person" && !actorPeerId) {
54
- throw new Error("openviking: peer_role=person requires a sender identity");
53
+ if (params.peerRole === "sender" && !actorPeerId) {
54
+ throw new Error("openviking: peer_role=sender requires a sender identity");
55
55
  }
56
56
  return actorPeerId;
57
57
  }
@@ -117,6 +117,8 @@ export type CompactOpenVikingSessionParams = {
117
117
  logger: ContextEngineLifecycleLogger;
118
118
  resolveAgentId: (sessionId: string, sessionKey?: string, ovSessionId?: string) => string;
119
119
  isBypassedSession: (params: { sessionId?: string; sessionKey?: string }) => boolean;
120
+ /** Host-native compaction for bypassed sessions; resolves undefined when unavailable. */
121
+ runtimeCompact?: () => Promise<CompactOpenVikingSessionResult | undefined>;
120
122
  diag: (stage: string, sessionId: string, data: Record<string, unknown>) => void;
121
123
  };
122
124
 
@@ -497,8 +499,8 @@ export async function assembleOpenVikingSession({
497
499
  const routingRef = sessionId ?? sessionKey ?? ovSessionId;
498
500
  const agentId = resolveAgentId(routingRef, sessionKey, ovSessionId);
499
501
  const actorPeerId = resolveOpenVikingActorPeerId({
500
- peerRole: cfg.peer_role ?? "assistant",
501
- personPeerId: sanitizeOpenVikingPeerId(sender.senderId),
502
+ peerRole: cfg.peer_role ?? "none",
503
+ senderPeerId: sanitizeOpenVikingPeerId(sender.senderId),
502
504
  assistantPeerId: agentId,
503
505
  });
504
506
  const queryConfig = await queryConfigStore?.getEffective({
@@ -910,9 +912,9 @@ export async function afterTurnOpenVikingSession({
910
912
  undefined,
911
913
  createdAt,
912
914
  resolveOpenVikingMessagePeerId({
913
- peerRole: cfg.peer_role ?? "assistant",
915
+ peerRole: cfg.peer_role ?? "none",
914
916
  role: msg.role,
915
- personPeerId: senderRoleId,
917
+ senderPeerId: senderRoleId,
916
918
  assistantPeerId: agentId,
917
919
  }),
918
920
  );
@@ -1014,6 +1016,7 @@ export async function compactOpenVikingSession({
1014
1016
  logger,
1015
1017
  resolveAgentId,
1016
1018
  isBypassedSession,
1019
+ runtimeCompact,
1017
1020
  diag,
1018
1021
  }: CompactOpenVikingSessionParams): Promise<CompactOpenVikingSessionResult> {
1019
1022
  const ovSessionId = openClawSessionToOvStorageId(sessionId, sessionKey);
@@ -1027,6 +1030,18 @@ export async function compactOpenVikingSession({
1027
1030
  });
1028
1031
 
1029
1032
  if (isBypassedSession({ sessionId, sessionKey })) {
1033
+ // Bypassed sessions store nothing in OV, but the host still needs a real
1034
+ // compaction (preflight hard-fails on an unknown skip reason), so hand the
1035
+ // request to OpenClaw's native compactor.
1036
+ const delegated = await runtimeCompact?.();
1037
+ if (delegated) {
1038
+ diag("compact_result", ovSessionId, {
1039
+ ok: delegated.ok,
1040
+ compacted: delegated.compacted,
1041
+ reason: delegated.reason ?? "session_bypassed_runtime_compaction",
1042
+ });
1043
+ return delegated;
1044
+ }
1030
1045
  diag("compact_result", ovSessionId, {
1031
1046
  ok: true,
1032
1047
  compacted: false,
@@ -13,6 +13,8 @@ import {
13
13
 
14
14
  export type { SetupIO, SlotActivationResult };
15
15
 
16
+ type SetupPeerRole = "none" | "assistant" | "sender" | "person";
17
+
16
18
  export type VersionCompatibility = "compatible" | "server_too_old" | "server_too_new" | "unknown";
17
19
 
18
20
  export type HealthResult = {
@@ -38,7 +40,7 @@ export type SetupResult = {
38
40
  mode: string;
39
41
  baseUrl: string;
40
42
  apiKey?: string;
41
- peer_role?: "none" | "assistant" | "person";
43
+ peer_role?: SetupPeerRole;
42
44
  peer_prefix?: string;
43
45
  accountId?: string;
44
46
  userId?: string;
@@ -57,7 +59,7 @@ export type StatusResult = {
57
59
  mode: string;
58
60
  baseUrl: string;
59
61
  hasApiKey: boolean;
60
- peer_role?: "none" | "assistant" | "person";
62
+ peer_role?: SetupPeerRole;
61
63
  peer_prefix?: string;
62
64
  hasAccountId: boolean;
63
65
  hasUserId: boolean;
@@ -71,7 +73,7 @@ export type SetupParams = {
71
73
  baseUrl: string;
72
74
  apiKey?: string;
73
75
  headers?: OpenVikingRequestHeaders;
74
- peerRole?: "none" | "assistant" | "person";
76
+ peerRole?: SetupPeerRole;
75
77
  peerPrefix?: string;
76
78
  accountId?: string;
77
79
  userId?: string;
@@ -85,7 +87,7 @@ export type InteractiveRemoteConfigParams = {
85
87
  baseUrl: string;
86
88
  apiKey?: string;
87
89
  headers?: OpenVikingRequestHeaders;
88
- peerRole?: "none" | "assistant" | "person";
90
+ peerRole?: SetupPeerRole;
89
91
  peerPrefix?: string;
90
92
  accountId?: string;
91
93
  userId?: string;
@@ -315,7 +317,7 @@ export function createOpenVikingSetupService({
315
317
  baseUrl,
316
318
  ...(apiKey ? { apiKey: maskKey(apiKey) } : {}),
317
319
  ...(headers ? { headers } : {}),
318
- ...(existing.peer_role ? { peer_role: String(existing.peer_role) as "none" | "assistant" | "person" } : {}),
320
+ ...(existing.peer_role ? { peer_role: String(existing.peer_role) as SetupPeerRole } : {}),
319
321
  ...(existing.peer_prefix ? { peer_prefix: String(existing.peer_prefix) } : {}),
320
322
  ...(existing.accountId ? { accountId: String(existing.accountId) } : {}),
321
323
  ...(existing.userId ? { userId: String(existing.userId) } : {}),
@@ -346,7 +348,7 @@ export function createOpenVikingSetupService({
346
348
  mode: String(existing.mode ?? "remote"),
347
349
  baseUrl,
348
350
  hasApiKey: !!existing.apiKey,
349
- ...(existing.peer_role ? { peer_role: String(existing.peer_role) as "none" | "assistant" | "person" } : {}),
351
+ ...(existing.peer_role ? { peer_role: String(existing.peer_role) as SetupPeerRole } : {}),
350
352
  ...(existing.peer_prefix ? { peer_prefix: String(existing.peer_prefix) } : {}),
351
353
  hasAccountId: !!existing.accountId,
352
354
  hasUserId: !!existing.userId,
@@ -106,7 +106,7 @@ Send this message:
106
106
  > 我需要 3 条信息,不知道的可以问你的管理员:
107
107
  > 1. **OpenViking 服务地址** —— 例如 `https://ov.example.com` 或 `http://192.168.1.100:1933`,本机服务可以直接说"本机"
108
108
  > 2. **API Key** —— 用来鉴权;服务没开认证可以说"没有"
109
- > 3. **Agent 标识前缀**(可选) —— 用于区分多个 agent 的记忆命名空间,留空就用默认
109
+ > 3. **记忆归属**(可选) —— 所有对话共用 user 记忆(默认),还是在 `peers/<assistant_id>` 或 `peers/<sender_id>` 下分开存放
110
110
  >
111
111
  > 先告诉我服务地址吧?
112
112
 
@@ -115,7 +115,7 @@ Send this message:
115
115
  > I need 3 things (ask your admin if unsure):
116
116
  > 1. **OpenViking server URL** — e.g. `https://ov.example.com` or `http://192.168.1.100:1933`. For a local server, just say "local".
117
117
  > 2. **API Key** — for auth. Say "none" if the server has no auth.
118
- > 3. **peer prefix** (optional) — used to namespace memories across agents. Leave blank for default.
118
+ > 3. **Memory scope** (optional) — shared user memory (default), or peer memory under `peers/<assistant_id>` / `peers/<sender_id>`.
119
119
  >
120
120
  > What's the server URL?
121
121
 
@@ -141,15 +141,36 @@ Collect 3 values through natural conversation. Be flexible: if the user gives se
141
141
  - "no" / "none" / "没有" / "空" / empty → `API_KEY=""` (you will skip the flag later).
142
142
  - Otherwise store as-is.
143
143
 
144
- ### 4c. `PEER_PREFIX` (OPTIONAL)
144
+ ### 4c. `PEER_ROLE` (OPTIONAL)
145
+
146
+ > (CN) 记忆要存在哪一层?默认共享在 `viking://user/<user_id>/memories`(`none`)。也可以按 OpenClaw 助手存到 `.../peers/<assistant_id>/memories`(`assistant`),或按发送者存到 `.../peers/<sender_id>/memories`(`sender`)。
147
+ > (EN) Where should memory live? The default is shared `viking://user/<user_id>/memories` (`none`). You can instead use `.../peers/<assistant_id>/memories` (`assistant`) or `.../peers/<sender_id>/memories` (`sender`).
148
+
149
+ Default to `none`. **Never silently pick another value** — the three options mean different storage layouts and are awkward to change later:
150
+
151
+ | Value | Concrete layout | Choose it when |
152
+ |---|---|---|
153
+ | `none` (default) | Shared memory under `viking://user/<user_id>/memories/...`; no concrete `peers/<peer_id>/memories` subtree is used. | General case. All conversations for this OpenViking user share user-level memory. |
154
+ | `assistant` | Assistant-attributed peer memory under `viking://user/<user_id>/peers/<assistant_id>/memories/...`, keyed by the resolved OpenClaw agent id (fallback `main`; optional prefix supported). | **Human as OpenViking user**: one human uses multiple assistants and wants their peer memories separated. Example: Alice's `main` and `research` assistants use `.../peers/main/...` and `.../peers/research/...`. |
155
+ | `sender` | Sender-attributed peer memory under `viking://user/<user_id>/peers/<sender_id>/memories/...`, keyed by the sender identity supplied by OpenClaw. | **Agent as OpenViking user**: one agent talks to multiple humans and wants their peer memories separated. Example: `support-agent` stores `customer-42` and `customer-99` under different peer subtrees. |
156
+
157
+ `person` is a legacy alias for `sender`. Accept it from an existing config or explicit user input, but normalize/write new setup values as `sender`.
158
+
159
+ OpenViking initializes the managed `peers/` container for every user. Do not tell the user that `none` removes that container: it only avoids a concrete peer memory subtree. With `assistant` or `sender`, actor-peer recall includes shared user memory plus the current peer memory; it hides other peer subtrees. Changing this setting does not move existing memories.
160
+
161
+ - Empty / "default" / "默认" / "共用" → leave unset (plugin defaults to `none`).
162
+ - Otherwise pass `--peer-role none|assistant|sender`. Treat explicit legacy `person` as `sender`. Any other value → ask again.
163
+
164
+ ### 4d. `PEER_PREFIX` (OPTIONAL, only when `PEER_ROLE=assistant`)
145
165
 
146
166
  > (CN) 想给这个 agent 一个记忆前缀吗?留空就用默认。只能用字母、数字、`_`、`-`。
147
167
  > (EN) Want to set an peer prefix? Leave blank for the default. Letters, digits, `_`, `-` only.
148
168
 
169
+ - Only meaningful when `PEER_ROLE=assistant`; skip the question otherwise.
149
170
  - Empty / "default" / "默认" → leave unset (plugin defaults to `""`).
150
171
  - Otherwise validate against `/^[A-Za-z0-9_-]+$/`. If invalid, ask again.
151
172
 
152
- ### 4d. (Conditional) Multi-Tenant Root-Key Fields
173
+ ### 4e. (Conditional) Multi-Tenant Root-Key Fields
153
174
 
154
175
  Only ask for these if STEP 7 detects a root key (`Root API key detected. Missing: --account-id, --user-id`). Don't ask up front.
155
176
 
@@ -259,14 +280,15 @@ Tell the user:
259
280
  Run the installer with `npx` (no global install needed):
260
281
 
261
282
  ```bash
262
- npx -y openclaw-openviking-setup-helper@latest --base-url BASE_URL [--api-key API_KEY] [--peer-prefix PEER_PREFIX] [--account-id ACCOUNT_ID] [--user-id USER_ID]
283
+ npx -y openclaw-openviking-setup-helper@latest --base-url BASE_URL [--api-key API_KEY] [--peer-role PEER_ROLE] [--peer-prefix PEER_PREFIX] [--account-id ACCOUNT_ID] [--user-id USER_ID]
263
284
  ```
264
285
 
265
286
  Build the flag list according to what the user gave you:
266
287
 
267
288
  - Always pass `--base-url BASE_URL`.
268
289
  - Pass `--api-key API_KEY` only if `API_KEY` is non-empty.
269
- - Pass `--peer-prefix PEER_PREFIX` only if the user gave one.
290
+ - Pass `--peer-role PEER_ROLE` only if the user chose `assistant` or `sender`; omit it for the `none` default. Normalize legacy `person` to `sender` first.
291
+ - Pass `--peer-prefix PEER_PREFIX` only if the user gave one and `PEER_ROLE=assistant`.
270
292
  - `--account-id` / `--user-id` only if the root-key path requires them.
271
293
 
272
294
  `ov-install` will, in one shot:
@@ -287,14 +309,15 @@ If `ov-install` exits non-zero, capture the last 30 lines of its output, show th
287
309
  Run the setup wizard non-interactively. Build flags from collected values:
288
310
 
289
311
  ```bash
290
- openclaw openviking setup --base-url BASE_URL --json [--api-key API_KEY] [--peer-prefix PEER_PREFIX] [--account-id ACCOUNT_ID] [--user-id USER_ID] [--allow-offline] [--force-slot]
312
+ openclaw openviking setup --base-url BASE_URL --json [--api-key API_KEY] [--peer-role PEER_ROLE] [--peer-prefix PEER_PREFIX] [--account-id ACCOUNT_ID] [--user-id USER_ID] [--allow-offline] [--force-slot]
291
313
  ```
292
314
 
293
315
  Rules:
294
316
 
295
317
  - `--base-url BASE_URL` is **required** under `--json`. Without it, the wizard prints `--json requires --base-url for non-interactive mode`.
296
318
  - `--api-key` only if `API_KEY` is non-empty.
297
- - `--peer-prefix` only if the user gave one. Use **`--peer-prefix`** for assistant peer prefixes; the old ID-style setup flag is no longer supported.
319
+ - `--peer-role` only if the user chose `assistant` or `sender`; omit it for the `none` default. Normalize legacy `person` to `sender` first.
320
+ - `--peer-prefix` only if the user gave one and `--peer-role assistant` is in play. Use **`--peer-prefix`** for assistant peer prefixes; the old ID-style setup flag is no longer supported.
298
321
  - `--account-id` / `--user-id` only after STEP 7 root-key detection (see below).
299
322
  - `--allow-offline` only if the user explicitly approved it in STEP 5.
300
323
  - `--force-slot` **never** in the first attempt. Add only after the user confirms (see slot_blocked handling below).
@@ -583,8 +606,8 @@ These are the keys under `plugins.entries.openviking.config` in `openclaw.json`.
583
606
  | `mode` | `"remote"` (forced by plugin) | Always remote in this skill. Don't set manually. |
584
607
  | `baseUrl` | `http://127.0.0.1:1933` | OpenViking server URL. |
585
608
  | `apiKey` | — | API key. Optional if server has no auth. |
586
- | `peer_role` | `assistant` | Peer identity mode: `none`, `assistant`, or `person`. Session messages use body `peer_id`; data-plane recall/search uses `X-OpenViking-Actor-Peer`. |
587
- | `peer_prefix` | `""` | Optional prefix for assistant `peer_id` / actor peer values when `peer_role=assistant`. Letters / digits / `_` / `-`. |
609
+ | `peer_role` | `none` | Memory scope: `none` (shared `viking://user/<user_id>/memories`), `assistant` (`.../peers/<assistant_id>/memories`), or `sender` (`.../peers/<sender_id>/memories`). Legacy `person` is accepted as `sender`. Session messages use body `peer_id`; data-plane recall/search uses `X-OpenViking-Actor-Peer`. |
610
+ | `peer_prefix` | `""` | Optional prefix for assistant `peer_id` / actor peer values. Only used when `peer_role=assistant`. Letters / digits / `_` / `-`. |
588
611
  | `accountId` | — | Required when `apiKey` is a root key. |
589
612
  | `userId` | — | Required when `apiKey` is a root key. |
590
613
  | `targetUri` | `viking://~/memories` | Default search scope URI. |
@@ -64,7 +64,7 @@ Core config lives under `plugins.entries.openviking.config`:
64
64
  |---|---:|---|
65
65
  | `baseUrl` | `http://127.0.0.1:1933` | OpenViking HTTP endpoint. Can also come from `OPENVIKING_BASE_URL` / `OPENVIKING_URL`. |
66
66
  | `apiKey` | empty | Optional API key. Can also come from `OPENVIKING_API_KEY`. |
67
- | `peer_role` | `assistant` | Peer identity mode: `none`, `assistant`, or `person`. Session messages use body `peer_id`; data-plane recall/search uses `X-OpenViking-Actor-Peer`. |
67
+ | `peer_role` | `none` | Memory scope: `none` (shared `viking://user/<user_id>/memories`), `assistant` (assistant-attributed memory under `.../peers/<assistant_id>/memories`), or `sender` (sender-attributed memory under `.../peers/<sender_id>/memories`). Legacy `person` is accepted as `sender`. |
68
68
  | `peer_prefix` | empty | Optional prefix for assistant `peer_id` / actor peer values when `peer_role=assistant`. |
69
69
  | `accountId` / `userId` | empty | Advanced tenant identity headers for root-key or trusted deployments. |
70
70
  | `targetUri` | `viking://~/memories` | Default search scope for legacy targeted memory search. |
@@ -95,7 +95,7 @@ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --json
95
95
  Useful variants:
96
96
 
97
97
  ```bash
98
- openclaw openviking setup --base-url <URL> --api-key <KEY> --peer-prefix openclaw-prod --json
98
+ openclaw openviking setup --base-url <URL> --api-key <KEY> --peer-role assistant --peer-prefix openclaw-prod --json
99
99
  openclaw openviking setup --base-url <URL> --api-key <ROOT_KEY> --account-id <ACCOUNT_ID> --user-id <USER_ID> --json
100
100
  openclaw openviking setup --base-url <URL> --api-key <KEY> --recall-target-types resource --json
101
101
  openclaw openviking setup --base-url <URL> --api-key <KEY> --allow-offline --json