@openviking/openclaw-plugin 2026.9.24 → 2026.10.1

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,7 +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
+ | Memory scope | Optional; default `none` | Ask whether memory is shared, separated by assistant, or separated by sender. Use `sender`. |
46
46
  | Account ID | Only for root API keys | Ask user if setup reports root-key tenant context is needed |
47
47
  | User ID | Only for root API keys | Ask user if setup reports root-key tenant context is needed |
48
48
  | Slot replacement approval | Only if another context engine owns the slot | Ask user before using `--force-slot` |
@@ -82,7 +82,7 @@ Choose memory scope before building that command:
82
82
  | `assistant` | Assistant-attributed peer memory under `.../peers/<assistant_id>/memories/...` | A human is the OpenViking user and uses multiple OpenClaw assistants |
83
83
  | `sender` | Sender-attributed peer memory under `.../peers/<sender_id>/memories/...` | An agent is the OpenViking user and receives messages from multiple humans |
84
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.
85
+ Setup rejects `person`; always pass `sender`. An existing config that still says `person` keeps working as `sender`. 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
86
 
87
87
  Examples:
88
88
 
package/INSTALL-ZH.md CHANGED
@@ -205,7 +205,7 @@ openclaw openviking setup --base-url <OPENVIKING_URL> --api-key <API_KEY> --forc
205
205
  | `assistant` | `viking://user/alice/peers/main/memories/...` | OpenViking user 代表人,并希望把 assistant 归因的 peer 记忆按不同 OpenClaw 助手分开。 |
206
206
  | `sender` | `viking://user/support-agent/peers/customer-42/memories/...` | OpenViking user 代表 agent,并希望把 sender 归因的 peer 记忆按不同发送者分开。 |
207
207
 
208
- `person` 仍作为 `sender` 的旧配置别名被兼容;新配置请使用 `sender`。
208
+ 安装和 setup 只接受 `sender`;已有配置里的 `person` 仍按 `sender` 生效。
209
209
 
210
210
  例如,让每个助手使用独立的 peer 记忆,并可选给 assistant id 加前缀:
211
211
 
@@ -405,7 +405,7 @@ ov-install
405
405
  | `--current-version` | 查看 helper 记录的当前版本 |
406
406
  | `--base-url URL` | OpenViking 服务器地址(启用非交互模式) |
407
407
  | `--api-key KEY` | OpenViking API key |
408
- | `--peer-role ROLE` | 记忆归属:`none`、`assistant` 或 `sender`;旧值 `person` 作为 `sender` 的别名兼容 |
408
+ | `--peer-role ROLE` | 记忆归属:`none`、`assistant` 或 `sender` |
409
409
  | `--peer-prefix PREFIX` | assistant `peer_id` / actor peer 值的前缀 |
410
410
  | `--update` | 更新 helper 管理的安装 |
411
411
 
package/INSTALL.md CHANGED
@@ -149,7 +149,7 @@ Choose `--peer-role` from what the OpenViking user represents:
149
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
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
151
 
152
- `person` is still accepted as a legacy alias for `sender`. New configuration should use `sender`.
152
+ Setup and the installer accept only `sender`. An existing config that still says `person` keeps working as `sender`.
153
153
 
154
154
  For example, give each assistant its own peer memory and optionally namespace the assistant id:
155
155
 
@@ -329,7 +329,7 @@ Useful backup/source flags:
329
329
  | `--current-version` | Print the version tracked by the helper |
330
330
  | `--base-url URL` | OpenViking server URL (enables non-interactive mode) |
331
331
  | `--api-key KEY` | OpenViking API key |
332
- | `--peer-role ROLE` | Memory scope: `none`, `assistant`, or `sender`; legacy `person` is accepted as `sender` |
332
+ | `--peer-role ROLE` | Memory scope: `none`, `assistant`, or `sender` |
333
333
  | `--peer-prefix PREFIX` | Prefix for assistant `peer_id` / actor peer values |
334
334
  | `--update` | Update an existing helper-managed install |
335
335
 
package/commands/setup.ts CHANGED
@@ -136,6 +136,12 @@ function normalizePeerRole(value: unknown): PeerRole | undefined {
136
136
  return undefined;
137
137
  }
138
138
 
139
+ // `person` survives only in existing configs; setup input must say `sender`.
140
+ function normalizePeerRoleInput(value: unknown): PeerRole | undefined {
141
+ if (typeof value === "string" && value.trim().toLowerCase() === "person") return undefined;
142
+ return normalizePeerRole(value);
143
+ }
144
+
139
145
  function resolveExistingPeerRole(existing: Record<string, unknown> | null | undefined): PeerRole {
140
146
  const explicit = normalizePeerRole(existing?.peer_role);
141
147
  if (explicit) return explicit;
@@ -151,9 +157,9 @@ function resolveExistingPeerPrefix(existing: Record<string, unknown> | null | un
151
157
 
152
158
  function resolveSetupPeerRole(value: unknown): PeerRole {
153
159
  if (value === undefined) return DEFAULT_SETUP_PEER_ROLE;
154
- const role = normalizePeerRole(value);
160
+ const role = normalizePeerRoleInput(value);
155
161
  if (role) return role;
156
- throw new Error('peer_role must be "none", "assistant", or "sender" (legacy alias: "person")');
162
+ throw new Error('peer_role must be "none", "assistant", or "sender" ("person" was renamed to "sender")');
157
163
  }
158
164
 
159
165
  function normalizeSetupRecallTargetTypes(value: unknown): RecallTargetType[] | undefined {
@@ -217,10 +223,10 @@ async function askPeerRole(
217
223
  zh,
218
224
  "Memory scope — none (default): viking://user/<user_id>/memories, shared across all conversations; " +
219
225
  "assistant: viking://user/<user_id>/peers/<assistant_id>/memories; " +
220
- "sender: viking://user/<user_id>/peers/<sender_id>/memories (legacy alias: person).",
226
+ "sender: viking://user/<user_id>/peers/<sender_id>/memories.",
221
227
  "记忆归属 —— none(默认):viking://user/<user_id>/memories,所有对话共享;" +
222
228
  "assistant:viking://user/<user_id>/peers/<assistant_id>/memories;" +
223
- "sender:viking://user/<user_id>/peers/<sender_id>/memories(兼容旧值 person)。",
229
+ "sender:viking://user/<user_id>/peers/<sender_id>/memories。",
224
230
  )}`,
225
231
  );
226
232
  while (true) {
@@ -228,13 +234,13 @@ async function askPeerRole(
228
234
  tr(zh, "Memory scope (none/assistant/sender)", "记忆归属(none/assistant/sender)"),
229
235
  defaultValue,
230
236
  );
231
- const role = normalizePeerRole(value);
237
+ const role = normalizePeerRoleInput(value);
232
238
  if (role) return role;
233
239
  console.log(
234
240
  ` ✗ ${tr(
235
241
  zh,
236
- 'Memory scope must be "none", "assistant", or "sender" (legacy "person" is also accepted).',
237
- '记忆归属必须是 "none"、"assistant" 或 "sender"(也兼容旧值 "person")。',
242
+ 'Memory scope must be "none", "assistant", or "sender" ("person" was renamed to "sender").',
243
+ '记忆归属必须是 "none"、"assistant" 或 "sender"("person" 已更名为 "sender")。',
238
244
  )}`,
239
245
  );
240
246
  }
@@ -496,7 +502,7 @@ export function registerSetupCli(api: any): void {
496
502
  .option("--zh", "Chinese prompts")
497
503
  .option("--base-url <url>", "OpenViking server URL (enables non-interactive mode)")
498
504
  .option("--api-key <key>", "API key for authentication")
499
- .option("--peer-role <role>", "Memory scope: none (shared), assistant (per assistant), or sender (per sender); person is a legacy alias")
505
+ .option("--peer-role <role>", "Memory scope: none (shared), assistant (per assistant), or sender (per sender)")
500
506
  .option("--peer-prefix <prefix>", "Prefix for assistant peer_id values")
501
507
  .option("--account-id <id>", "Account ID (required for root API keys)")
502
508
  .option("--user-id <id>", "User ID (required for root API keys)")
@@ -106,6 +106,12 @@ function normalizePeerRole(value) {
106
106
  return role;
107
107
  return undefined;
108
108
  }
109
+ // `person` survives only in existing configs; setup input must say `sender`.
110
+ function normalizePeerRoleInput(value) {
111
+ if (typeof value === "string" && value.trim().toLowerCase() === "person")
112
+ return undefined;
113
+ return normalizePeerRole(value);
114
+ }
109
115
  function resolveExistingPeerRole(existing) {
110
116
  const explicit = normalizePeerRole(existing?.peer_role);
111
117
  if (explicit)
@@ -122,10 +128,10 @@ function resolveExistingPeerPrefix(existing) {
122
128
  function resolveSetupPeerRole(value) {
123
129
  if (value === undefined)
124
130
  return DEFAULT_SETUP_PEER_ROLE;
125
- const role = normalizePeerRole(value);
131
+ const role = normalizePeerRoleInput(value);
126
132
  if (role)
127
133
  return role;
128
- throw new Error('peer_role must be "none", "assistant", or "sender" (legacy alias: "person")');
134
+ throw new Error('peer_role must be "none", "assistant", or "sender" ("person" was renamed to "sender")');
129
135
  }
130
136
  function normalizeSetupRecallTargetTypes(value) {
131
137
  if (value === undefined || value === null || value === "") {
@@ -178,15 +184,15 @@ function preserveCurrentConfig(existing) {
178
184
  async function askPeerRole(zh, q, defaultValue) {
179
185
  console.log(` ${tr(zh, "Memory scope — none (default): viking://user/<user_id>/memories, shared across all conversations; " +
180
186
  "assistant: viking://user/<user_id>/peers/<assistant_id>/memories; " +
181
- "sender: viking://user/<user_id>/peers/<sender_id>/memories (legacy alias: person).", "记忆归属 —— none(默认):viking://user/<user_id>/memories,所有对话共享;" +
187
+ "sender: viking://user/<user_id>/peers/<sender_id>/memories.", "记忆归属 —— none(默认):viking://user/<user_id>/memories,所有对话共享;" +
182
188
  "assistant:viking://user/<user_id>/peers/<assistant_id>/memories;" +
183
- "sender:viking://user/<user_id>/peers/<sender_id>/memories(兼容旧值 person)。")}`);
189
+ "sender:viking://user/<user_id>/peers/<sender_id>/memories。")}`);
184
190
  while (true) {
185
191
  const value = await q(tr(zh, "Memory scope (none/assistant/sender)", "记忆归属(none/assistant/sender)"), defaultValue);
186
- const role = normalizePeerRole(value);
192
+ const role = normalizePeerRoleInput(value);
187
193
  if (role)
188
194
  return role;
189
- console.log(` ✗ ${tr(zh, 'Memory scope must be "none", "assistant", or "sender" (legacy "person" is also accepted).', '记忆归属必须是 "none"、"assistant" 或 "sender"(也兼容旧值 "person")。')}`);
195
+ console.log(` ✗ ${tr(zh, 'Memory scope must be "none", "assistant", or "sender" ("person" was renamed to "sender").', '记忆归属必须是 "none"、"assistant" 或 "sender"("person" 已更名为 "sender")。')}`);
190
196
  }
191
197
  }
192
198
  async function askPeerPrefix(zh, q, defaultValue) {
@@ -375,7 +381,7 @@ export function registerSetupCli(api) {
375
381
  .option("--zh", "Chinese prompts")
376
382
  .option("--base-url <url>", "OpenViking server URL (enables non-interactive mode)")
377
383
  .option("--api-key <key>", "API key for authentication")
378
- .option("--peer-role <role>", "Memory scope: none (shared), assistant (per assistant), or sender (per sender); person is a legacy alias")
384
+ .option("--peer-role <role>", "Memory scope: none (shared), assistant (per assistant), or sender (per sender)")
379
385
  .option("--peer-prefix <prefix>", "Prefix for assistant peer_id values")
380
386
  .option("--account-id <id>", "Account ID (required for root API keys)")
381
387
  .option("--user-id <id>", "User ID (required for root API keys)")
@@ -50,6 +50,7 @@ export function createOpenVikingSessionRoutingRuntime(options) {
50
50
  peerRole,
51
51
  senderPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
52
52
  assistantPeerId: agentId,
53
+ warn: (message) => options.logger.warn(message),
53
54
  }),
54
55
  };
55
56
  };
@@ -20,13 +20,21 @@ export function resolveOpenVikingMessagePeerId(params) {
20
20
  }
21
21
  return undefined;
22
22
  }
23
+ /**
24
+ * Peer scoping is soft isolation. OpenClaw does not hand every path a sender
25
+ * (context-engine assemble gets no runtimeContext; cron and heartbeat turns
26
+ * have no sender at all), so a missing one widens to the unscoped request a
27
+ * caller without X-OpenViking-Actor-Peer gets, with a warning, rather than
28
+ * taking OpenViking away for the turn.
29
+ */
23
30
  export function resolveOpenVikingActorPeerId(params) {
24
31
  const actorPeerId = resolveOpenVikingMessagePeerId({
25
32
  ...params,
26
33
  role: params.peerRole === "sender" ? "user" : "assistant",
27
34
  });
28
35
  if (params.peerRole === "sender" && !actorPeerId) {
29
- throw new Error("openviking: peer_role=sender requires a sender identity");
36
+ params.warn?.("openviking: peer_role=sender but OpenClaw supplied no sender identity; " +
37
+ "continuing as an unscoped request under this user (no X-OpenViking-Actor-Peer)");
30
38
  }
31
39
  return actorPeerId;
32
40
  }
@@ -207,6 +207,7 @@ async function recallForAssemble(params, recallQuery) {
207
207
  peerRole: cfg.peer_role ?? "none",
208
208
  senderPeerId: sanitizeOpenVikingPeerId(sender.senderId),
209
209
  assistantPeerId: agentId,
210
+ warn: (message) => logger.warn?.(message),
210
211
  });
211
212
  const queryConfig = await queryConfigStore?.getEffective({
212
213
  agentId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openviking/openclaw-plugin",
3
- "version": "2026.9.24",
3
+ "version": "2026.10.1",
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",
@@ -9,6 +9,7 @@ import {
9
9
 
10
10
  type Logger = {
11
11
  info: (message: string) => void;
12
+ warn: (message: string) => void;
12
13
  };
13
14
 
14
15
  export type SessionAgentLookup = {
@@ -99,6 +100,7 @@ export function createOpenVikingSessionRoutingRuntime(options: {
99
100
  peerRole,
100
101
  senderPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
101
102
  assistantPeerId: agentId,
103
+ warn: (message) => options.logger.warn(message),
102
104
  }),
103
105
  };
104
106
  };
@@ -41,17 +41,28 @@ export function resolveOpenVikingMessagePeerId(params: {
41
41
  return undefined;
42
42
  }
43
43
 
44
+ /**
45
+ * Peer scoping is soft isolation. OpenClaw does not hand every path a sender
46
+ * (context-engine assemble gets no runtimeContext; cron and heartbeat turns
47
+ * have no sender at all), so a missing one widens to the unscoped request a
48
+ * caller without X-OpenViking-Actor-Peer gets, with a warning, rather than
49
+ * taking OpenViking away for the turn.
50
+ */
44
51
  export function resolveOpenVikingActorPeerId(params: {
45
52
  peerRole: OpenVikingPeerRole;
46
53
  senderPeerId?: string;
47
54
  assistantPeerId?: string;
55
+ warn?: (message: string) => void;
48
56
  }): string | undefined {
49
57
  const actorPeerId = resolveOpenVikingMessagePeerId({
50
58
  ...params,
51
59
  role: params.peerRole === "sender" ? "user" : "assistant",
52
60
  });
53
61
  if (params.peerRole === "sender" && !actorPeerId) {
54
- throw new Error("openviking: peer_role=sender requires a sender identity");
62
+ params.warn?.(
63
+ "openviking: peer_role=sender but OpenClaw supplied no sender identity; " +
64
+ "continuing as an unscoped request under this user (no X-OpenViking-Actor-Peer)",
65
+ );
55
66
  }
56
67
  return actorPeerId;
57
68
  }
@@ -440,6 +440,7 @@ async function recallForAssemble(
440
440
  peerRole: cfg.peer_role ?? "none",
441
441
  senderPeerId: sanitizeOpenVikingPeerId(sender.senderId),
442
442
  assistantPeerId: agentId,
443
+ warn: (message) => logger.warn?.(message),
443
444
  });
444
445
  const queryConfig = await queryConfigStore?.getEffective({
445
446
  agentId,