@openviking/openclaw-plugin 2026.9.23 → 2026.9.24-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 +2 -2
- package/INSTALL-ZH.md +2 -2
- package/INSTALL.md +2 -2
- package/commands/setup.ts +14 -8
- package/dist/commands/setup.js +13 -7
- package/dist/plugin/openviking-session-routing-runtime.js +1 -0
- package/dist/routing/identity-routing.js +9 -1
- package/dist/services/context-lifecycle-service.js +1 -0
- package/package.json +1 -1
- package/plugin/openviking-session-routing-runtime.ts +2 -0
- package/routing/identity-routing.ts +12 -1
- package/services/context-lifecycle-service.ts +1 -0
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
|
|
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
|
|
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`
|
|
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
|
|
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
|
-
|
|
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
|
|
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 =
|
|
160
|
+
const role = normalizePeerRoleInput(value);
|
|
155
161
|
if (role) return role;
|
|
156
|
-
throw new Error('peer_role must be "none", "assistant", or "sender" (
|
|
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
|
|
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
|
|
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 =
|
|
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" (
|
|
237
|
-
'记忆归属必须是 "none"、"assistant" 或 "sender"
|
|
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)
|
|
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)")
|
package/dist/commands/setup.js
CHANGED
|
@@ -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 =
|
|
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" (
|
|
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
|
|
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
|
|
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 =
|
|
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" (
|
|
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)
|
|
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)")
|
|
@@ -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
|
-
|
|
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.
|
|
3
|
+
"version": "2026.9.24-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
|
-
|
|
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,
|