@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, requestTimeoutMs?: number): Promise<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
- requestTimeoutMs,
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, requestTimeoutMs) {
248
- return this.request(`/api/v1/content/read?uri=${encodeURIComponent(uri)}`, {}, requestTimeoutMs, actorPeerId);
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
- const PROFILE_MAX_CHARS = 8000;
200
- const PROFILE_READ_TIMEOUT_MS = 3000;
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.isBypassedSession(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
- try {
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, await getClient(), resolveAssembleRouting(params));
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: session history not assembled because OV session does not exist ` +
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-1",
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
- const PROFILE_MAX_CHARS = 8000;
432
- const PROFILE_READ_TIMEOUT_MS = 3000;
433
-
434
- function resolveAssembleRouting(params: AssembleOpenVikingSessionParams) {
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 (!params.isMainAssemble || !params.cfg.autoRecall || params.isBypassedSession(params)) {
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 routing = resolveAssembleRouting(params);
523
- const client = await params.getClient();
524
- const [profileBlock, recallBlock] = await Promise.all([
525
- readProfileBlock(
526
- client,
527
- routing.actorPeerId,
528
- Math.min(params.cfg.autoRecallTimeoutMs ?? PROFILE_READ_TIMEOUT_MS, PROFILE_READ_TIMEOUT_MS),
529
- params.logger,
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, await getClient(), resolveAssembleRouting(params));
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: session history not assembled because OV session does not exist ` +
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({