@openviking/openclaw-plugin 2026.10.7-1 → 2026.10.7
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/client.ts
CHANGED
|
@@ -554,11 +554,11 @@ export class OpenVikingClient {
|
|
|
554
554
|
};
|
|
555
555
|
}
|
|
556
556
|
|
|
557
|
-
async read(uri: string, actorPeerId?: string
|
|
557
|
+
async read(uri: string, actorPeerId?: string): Promise<string> {
|
|
558
558
|
return this.request<string>(
|
|
559
559
|
`/api/v1/content/read?uri=${encodeURIComponent(uri)}`,
|
|
560
560
|
{},
|
|
561
|
-
|
|
561
|
+
undefined,
|
|
562
562
|
actorPeerId,
|
|
563
563
|
);
|
|
564
564
|
}
|
package/dist/client.js
CHANGED
|
@@ -244,8 +244,8 @@ export class OpenVikingClient {
|
|
|
244
244
|
: result.entries,
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
|
-
async read(uri, actorPeerId
|
|
248
|
-
return this.request(`/api/v1/content/read?uri=${encodeURIComponent(uri)}`, {},
|
|
247
|
+
async read(uri, actorPeerId) {
|
|
248
|
+
return this.request(`/api/v1/content/read?uri=${encodeURIComponent(uri)}`, {}, undefined, actorPeerId);
|
|
249
249
|
}
|
|
250
250
|
async list(uri, options) {
|
|
251
251
|
const normalizedUri = uri.trim().replace(/\/+$/, "");
|
|
@@ -196,12 +196,11 @@ function isSessionNotFoundError(err) {
|
|
|
196
196
|
const errorMessage = String(err);
|
|
197
197
|
return errorMessage.includes("[NOT_FOUND]") && errorMessage.includes("Session not found");
|
|
198
198
|
}
|
|
199
|
-
|
|
200
|
-
const
|
|
201
|
-
function resolveAssembleRouting(params) {
|
|
202
|
-
const { sessionId, sessionKey, cfg, resolveAgentId, logger } = params;
|
|
199
|
+
async function recallForAssemble(params, recallQuery) {
|
|
200
|
+
const { sessionId, sessionKey, cfg, getClient, resolveAgentId, queryConfigStore, logger, traceRecorder } = params;
|
|
203
201
|
const ovSessionId = openClawSessionToOvStorageId(sessionId, sessionKey);
|
|
204
202
|
const sender = extractRuntimeSenderId(params.runtimeContext);
|
|
203
|
+
const client = await getClient();
|
|
205
204
|
const routingRef = sessionId ?? sessionKey ?? ovSessionId;
|
|
206
205
|
const agentId = resolveAgentId(routingRef, sessionKey, ovSessionId);
|
|
207
206
|
const actorPeerId = resolveOpenVikingActorPeerId({
|
|
@@ -210,34 +209,6 @@ function resolveAssembleRouting(params) {
|
|
|
210
209
|
assistantPeerId: agentId,
|
|
211
210
|
warn: (message) => logger.warn?.(message),
|
|
212
211
|
});
|
|
213
|
-
return { ovSessionId, agentId, actorPeerId };
|
|
214
|
-
}
|
|
215
|
-
// Server-side context assembly leaves profile.md out on the assumption that the
|
|
216
|
-
// client injects it, so read it here: the user's profile and, with peer scope, the actor's.
|
|
217
|
-
async function readProfileBlock(client, actorPeerId, timeoutMs, logger) {
|
|
218
|
-
const uris = ["viking://~/memories/profile.md"];
|
|
219
|
-
if (actorPeerId)
|
|
220
|
-
uris.push(`viking://~/peers/${actorPeerId}/memories/profile.md`);
|
|
221
|
-
const reads = await Promise.allSettled(uris.map((uri) => client.read(uri, actorPeerId, timeoutMs)));
|
|
222
|
-
return reads
|
|
223
|
-
.map((read, i) => {
|
|
224
|
-
if (read.status === "rejected" && !String(read.reason).includes("[NOT_FOUND]")) {
|
|
225
|
-
logger.warn?.(`openviking: profile read failed (uri=${uris[i]}): ${String(read.reason)}`);
|
|
226
|
-
}
|
|
227
|
-
const text = read.status === "fulfilled" && typeof read.value === "string" ? read.value.trim() : "";
|
|
228
|
-
if (!text)
|
|
229
|
-
return "";
|
|
230
|
-
const capped = text.length > PROFILE_MAX_CHARS
|
|
231
|
-
? `${text.slice(0, PROFILE_MAX_CHARS).trimEnd()}\n... [profile truncated]`
|
|
232
|
-
: text;
|
|
233
|
-
return `<user-profile uri="${uris[i]}">\n${capped}\n</user-profile>`;
|
|
234
|
-
})
|
|
235
|
-
.filter(Boolean)
|
|
236
|
-
.join("\n\n");
|
|
237
|
-
}
|
|
238
|
-
async function recallForAssemble(params, recallQuery, client, routing) {
|
|
239
|
-
const { sessionId, sessionKey, cfg, queryConfigStore, logger, traceRecorder } = params;
|
|
240
|
-
const { ovSessionId, agentId, actorPeerId } = routing;
|
|
241
212
|
const queryConfig = await queryConfigStore?.getEffective({
|
|
242
213
|
agentId,
|
|
243
214
|
sessionId,
|
|
@@ -267,32 +238,24 @@ export async function assembleOpenVikingSession(params) {
|
|
|
267
238
|
const assembled = await assembleSessionContext(params);
|
|
268
239
|
// Current OpenClaw supplies the pending turn separately from history. Keep
|
|
269
240
|
// recalled context out of persisted messages and let the host own that turn.
|
|
270
|
-
if (!params.isMainAssemble || !params.cfg.autoRecall || params.
|
|
241
|
+
if (!params.isMainAssemble || !params.cfg.autoRecall || !params.prompt ||
|
|
242
|
+
params.isBypassedSession(params)) {
|
|
271
243
|
return assembled;
|
|
272
244
|
}
|
|
273
|
-
const query = prepareRecallQuery(params.prompt
|
|
274
|
-
|
|
275
|
-
const routing = resolveAssembleRouting(params);
|
|
276
|
-
const client = await params.getClient();
|
|
277
|
-
const [profileBlock, recallBlock] = await Promise.all([
|
|
278
|
-
readProfileBlock(client, routing.actorPeerId, Math.min(params.cfg.autoRecallTimeoutMs ?? PROFILE_READ_TIMEOUT_MS, PROFILE_READ_TIMEOUT_MS), params.logger),
|
|
279
|
-
query.query.length < 5 ? "" : recallForAssemble(params, query, client, routing)
|
|
280
|
-
.then((recall) => recall.block)
|
|
281
|
-
.catch((err) => {
|
|
282
|
-
params.logger.warn?.(`openviking: auto-recall failed: ${String(err)}`);
|
|
283
|
-
return "";
|
|
284
|
-
}),
|
|
285
|
-
]);
|
|
286
|
-
const baseTokens = estimateTextTokens(assembled.systemPromptAddition ?? "");
|
|
287
|
-
for (const blocks of [[profileBlock, recallBlock], [profileBlock], [recallBlock]]) {
|
|
288
|
-
if (!blocks.some(Boolean))
|
|
289
|
-
continue;
|
|
290
|
-
const systemPromptAddition = [assembled.systemPromptAddition, ...blocks].filter(Boolean).join("\n\n");
|
|
291
|
-
const estimatedTokens = assembled.estimatedTokens + estimateTextTokens(systemPromptAddition) - baseTokens;
|
|
292
|
-
if (estimatedTokens <= params.tokenBudget)
|
|
293
|
-
return { ...assembled, systemPromptAddition, estimatedTokens };
|
|
294
|
-
}
|
|
245
|
+
const query = prepareRecallQuery(params.prompt);
|
|
246
|
+
if (query.query.length < 5)
|
|
295
247
|
return assembled;
|
|
248
|
+
try {
|
|
249
|
+
const recall = await recallForAssemble(params, query);
|
|
250
|
+
if (!recall.block)
|
|
251
|
+
return assembled;
|
|
252
|
+
const systemPromptAddition = [assembled.systemPromptAddition, recall.block].filter(Boolean).join("\n\n");
|
|
253
|
+
const estimatedTokens = assembled.estimatedTokens
|
|
254
|
+
+ estimateTextTokens(systemPromptAddition)
|
|
255
|
+
- estimateTextTokens(assembled.systemPromptAddition ?? "");
|
|
256
|
+
if (estimatedTokens > params.tokenBudget)
|
|
257
|
+
return assembled;
|
|
258
|
+
return { ...assembled, systemPromptAddition, estimatedTokens };
|
|
296
259
|
}
|
|
297
260
|
catch (err) {
|
|
298
261
|
params.logger.warn?.(`openviking: auto-recall failed: ${String(err)}`);
|
|
@@ -344,7 +307,7 @@ async function assembleSessionContext(params) {
|
|
|
344
307
|
`chars=${recallQuery.originalChars}->${recallQuery.finalChars})`);
|
|
345
308
|
}
|
|
346
309
|
try {
|
|
347
|
-
const recall = await recallForAssemble(params, recallQuery
|
|
310
|
+
const recall = await recallForAssemble(params, recallQuery);
|
|
348
311
|
if (!recall.block) {
|
|
349
312
|
return assemblePassthrough({
|
|
350
313
|
diag,
|
|
@@ -459,7 +422,7 @@ async function assembleSessionContext(params) {
|
|
|
459
422
|
catch (err) {
|
|
460
423
|
if (isSessionNotFoundError(err)) {
|
|
461
424
|
const errorMessage = String(err);
|
|
462
|
-
logger.info(`openviking:
|
|
425
|
+
logger.info(`openviking: assemble skipped because OV session does not exist ` +
|
|
463
426
|
`(session=${ovSessionId}, tokenBudget=${tokenBudget}, agentId=${resolveAgentId(ovSessionId)})`);
|
|
464
427
|
return assemblePassthrough({
|
|
465
428
|
diag,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openviking/openclaw-plugin",
|
|
3
|
-
"version": "2026.10.7
|
|
3
|
+
"version": "2026.10.7",
|
|
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",
|
|
@@ -428,13 +428,14 @@ function isSessionNotFoundError(err: unknown): boolean {
|
|
|
428
428
|
return errorMessage.includes("[NOT_FOUND]") && errorMessage.includes("Session not found");
|
|
429
429
|
}
|
|
430
430
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const { sessionId, sessionKey, cfg, resolveAgentId, logger } = params;
|
|
431
|
+
async function recallForAssemble(
|
|
432
|
+
params: AssembleOpenVikingSessionParams,
|
|
433
|
+
recallQuery: ReturnType<typeof prepareRecallQuery>,
|
|
434
|
+
) {
|
|
435
|
+
const { sessionId, sessionKey, cfg, getClient, resolveAgentId, queryConfigStore, logger, traceRecorder } = params;
|
|
436
436
|
const ovSessionId = openClawSessionToOvStorageId(sessionId, sessionKey);
|
|
437
437
|
const sender = extractRuntimeSenderId(params.runtimeContext);
|
|
438
|
+
const client = await getClient();
|
|
438
439
|
const routingRef = sessionId ?? sessionKey ?? ovSessionId;
|
|
439
440
|
const agentId = resolveAgentId(routingRef, sessionKey, ovSessionId);
|
|
440
441
|
const actorPeerId = resolveOpenVikingActorPeerId({
|
|
@@ -443,44 +444,6 @@ function resolveAssembleRouting(params: AssembleOpenVikingSessionParams) {
|
|
|
443
444
|
assistantPeerId: agentId,
|
|
444
445
|
warn: (message) => logger.warn?.(message),
|
|
445
446
|
});
|
|
446
|
-
return { ovSessionId, agentId, actorPeerId };
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
// Server-side context assembly leaves profile.md out on the assumption that the
|
|
450
|
-
// client injects it, so read it here: the user's profile and, with peer scope, the actor's.
|
|
451
|
-
async function readProfileBlock(
|
|
452
|
-
client: OpenVikingClient,
|
|
453
|
-
actorPeerId: string | undefined,
|
|
454
|
-
timeoutMs: number,
|
|
455
|
-
logger: ContextEngineLifecycleLogger,
|
|
456
|
-
): Promise<string> {
|
|
457
|
-
const uris = ["viking://~/memories/profile.md"];
|
|
458
|
-
if (actorPeerId) uris.push(`viking://~/peers/${actorPeerId}/memories/profile.md`);
|
|
459
|
-
const reads = await Promise.allSettled(uris.map((uri) => client.read(uri, actorPeerId, timeoutMs)));
|
|
460
|
-
return reads
|
|
461
|
-
.map((read, i) => {
|
|
462
|
-
if (read.status === "rejected" && !String(read.reason).includes("[NOT_FOUND]")) {
|
|
463
|
-
logger.warn?.(`openviking: profile read failed (uri=${uris[i]}): ${String(read.reason)}`);
|
|
464
|
-
}
|
|
465
|
-
const text = read.status === "fulfilled" && typeof read.value === "string" ? read.value.trim() : "";
|
|
466
|
-
if (!text) return "";
|
|
467
|
-
const capped = text.length > PROFILE_MAX_CHARS
|
|
468
|
-
? `${text.slice(0, PROFILE_MAX_CHARS).trimEnd()}\n... [profile truncated]`
|
|
469
|
-
: text;
|
|
470
|
-
return `<user-profile uri="${uris[i]}">\n${capped}\n</user-profile>`;
|
|
471
|
-
})
|
|
472
|
-
.filter(Boolean)
|
|
473
|
-
.join("\n\n");
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
async function recallForAssemble(
|
|
477
|
-
params: AssembleOpenVikingSessionParams,
|
|
478
|
-
recallQuery: ReturnType<typeof prepareRecallQuery>,
|
|
479
|
-
client: OpenVikingClient,
|
|
480
|
-
routing: ReturnType<typeof resolveAssembleRouting>,
|
|
481
|
-
) {
|
|
482
|
-
const { sessionId, sessionKey, cfg, queryConfigStore, logger, traceRecorder } = params;
|
|
483
|
-
const { ovSessionId, agentId, actorPeerId } = routing;
|
|
484
447
|
const queryConfig = await queryConfigStore?.getEffective({
|
|
485
448
|
agentId,
|
|
486
449
|
sessionId,
|
|
@@ -513,36 +476,24 @@ export async function assembleOpenVikingSession(
|
|
|
513
476
|
const assembled = await assembleSessionContext(params);
|
|
514
477
|
// Current OpenClaw supplies the pending turn separately from history. Keep
|
|
515
478
|
// recalled context out of persisted messages and let the host own that turn.
|
|
516
|
-
if (
|
|
479
|
+
if (
|
|
480
|
+
!params.isMainAssemble || !params.cfg.autoRecall || !params.prompt ||
|
|
481
|
+
params.isBypassedSession(params)
|
|
482
|
+
) {
|
|
517
483
|
return assembled;
|
|
518
484
|
}
|
|
519
|
-
const query = prepareRecallQuery(params.prompt
|
|
485
|
+
const query = prepareRecallQuery(params.prompt);
|
|
486
|
+
if (query.query.length < 5) return assembled;
|
|
520
487
|
|
|
521
488
|
try {
|
|
522
|
-
const
|
|
523
|
-
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
),
|
|
531
|
-
query.query.length < 5 ? "" : recallForAssemble(params, query, client, routing)
|
|
532
|
-
.then((recall) => recall.block)
|
|
533
|
-
.catch((err) => {
|
|
534
|
-
params.logger.warn?.(`openviking: auto-recall failed: ${String(err)}`);
|
|
535
|
-
return "";
|
|
536
|
-
}),
|
|
537
|
-
]);
|
|
538
|
-
const baseTokens = estimateTextTokens(assembled.systemPromptAddition ?? "");
|
|
539
|
-
for (const blocks of [[profileBlock, recallBlock], [profileBlock], [recallBlock]]) {
|
|
540
|
-
if (!blocks.some(Boolean)) continue;
|
|
541
|
-
const systemPromptAddition = [assembled.systemPromptAddition, ...blocks].filter(Boolean).join("\n\n");
|
|
542
|
-
const estimatedTokens = assembled.estimatedTokens + estimateTextTokens(systemPromptAddition) - baseTokens;
|
|
543
|
-
if (estimatedTokens <= params.tokenBudget) return { ...assembled, systemPromptAddition, estimatedTokens };
|
|
544
|
-
}
|
|
545
|
-
return assembled;
|
|
489
|
+
const recall = await recallForAssemble(params, query);
|
|
490
|
+
if (!recall.block) return assembled;
|
|
491
|
+
const systemPromptAddition = [assembled.systemPromptAddition, recall.block].filter(Boolean).join("\n\n");
|
|
492
|
+
const estimatedTokens = assembled.estimatedTokens
|
|
493
|
+
+ estimateTextTokens(systemPromptAddition)
|
|
494
|
+
- estimateTextTokens(assembled.systemPromptAddition ?? "");
|
|
495
|
+
if (estimatedTokens > params.tokenBudget) return assembled;
|
|
496
|
+
return { ...assembled, systemPromptAddition, estimatedTokens };
|
|
546
497
|
} catch (err) {
|
|
547
498
|
params.logger.warn?.(`openviking: auto-recall failed: ${String(err)}`);
|
|
548
499
|
return assembled;
|
|
@@ -622,7 +573,7 @@ async function assembleSessionContext(params: AssembleOpenVikingSessionParams):
|
|
|
622
573
|
}
|
|
623
574
|
|
|
624
575
|
try {
|
|
625
|
-
const recall = await recallForAssemble(params, recallQuery
|
|
576
|
+
const recall = await recallForAssemble(params, recallQuery);
|
|
626
577
|
|
|
627
578
|
if (!recall.block) {
|
|
628
579
|
return assemblePassthrough({
|
|
@@ -756,7 +707,7 @@ async function assembleSessionContext(params: AssembleOpenVikingSessionParams):
|
|
|
756
707
|
if (isSessionNotFoundError(err)) {
|
|
757
708
|
const errorMessage = String(err);
|
|
758
709
|
logger.info(
|
|
759
|
-
`openviking:
|
|
710
|
+
`openviking: assemble skipped because OV session does not exist ` +
|
|
760
711
|
`(session=${ovSessionId}, tokenBudget=${tokenBudget}, agentId=${resolveAgentId(ovSessionId)})`,
|
|
761
712
|
);
|
|
762
713
|
return assemblePassthrough({
|