@openviking/openclaw-plugin 2026.10.6 → 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/README.md +3 -1
- package/client.ts +5 -0
- package/commands/setup.ts +1 -0
- package/config.ts +6 -0
- package/context-engine.ts +3 -2
- package/dist/client.js +3 -0
- package/dist/commands/setup.js +1 -0
- package/dist/config.js +5 -0
- package/dist/context-engine.js +2 -1
- package/dist/plugin/openviking-memory-tools.js +24 -6
- package/dist/services/context-lifecycle-service.js +24 -1
- package/install-manifest.json +1 -1
- package/openclaw.plugin.json +6 -0
- package/package.json +1 -1
- package/plugin/openviking-memory-tools.ts +26 -7
- package/services/context-lifecycle-service.ts +34 -0
- package/skills/ov-experience-memory/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# OpenViking for OpenClaw
|
|
2
2
|
|
|
3
|
+
> **Working memory is now opt-in.** Update installed plugins separately from the OV server, then restart the host. Existing explicit settings still take precedence. See the [default-off upgrade guide](../../docs/en/guides/working-memory-default-off.md) for native history, re-enabling WM, and old-conversation handoffs.
|
|
4
|
+
|
|
3
5
|
Use [OpenViking](https://github.com/volcengine/OpenViking) as OpenClaw's long-term context engine: automatic recall, session archive, memory extraction, semantic search, and RAG over a remote OpenViking server.
|
|
4
6
|
|
|
5
7
|
## Quick Start
|
|
@@ -243,7 +245,7 @@ Use it as a complement to auto-capture, not a replacement:
|
|
|
243
245
|
|
|
244
246
|
- auto-capture still preserves ordinary conversation flow and batches extraction for cost and latency
|
|
245
247
|
- `memory_store` is for explicit durable-memory intent such as "remember my main project is X" or "save this preference"
|
|
246
|
-
- if `memory_store` commits but extracts 0 memories,
|
|
248
|
+
- if `memory_store` commits but extracts 0 memories, it returns `action: "failed"` with `error: "no_memories_extracted"` and the agent tells the user no new memory was created; possible causes are that the content is already stored, extraction is disabled, or the extraction/model configuration needs checking
|
|
247
249
|
|
|
248
250
|
### What `compact()` does
|
|
249
251
|
|
package/client.ts
CHANGED
|
@@ -75,6 +75,7 @@ export type OpenVikingClientOptions = {
|
|
|
75
75
|
};
|
|
76
76
|
|
|
77
77
|
export type CommitSessionResult = {
|
|
78
|
+
effective_enable_working_memory?: boolean;
|
|
78
79
|
session_id: string;
|
|
79
80
|
/** "accepted" (async), "skipped" (no archive), "completed", "failed", or "timeout" (wait mode). */
|
|
80
81
|
status: string;
|
|
@@ -841,6 +842,7 @@ export class OpenVikingClient {
|
|
|
841
842
|
sessionId: string,
|
|
842
843
|
options?: {
|
|
843
844
|
wait?: boolean;
|
|
845
|
+
enableWorkingMemory?: boolean;
|
|
844
846
|
timeoutMs?: number;
|
|
845
847
|
/**
|
|
846
848
|
* WM v2: number of most-recent messages to keep live after commit.
|
|
@@ -871,6 +873,9 @@ export class OpenVikingClient {
|
|
|
871
873
|
options?.agentId,
|
|
872
874
|
);
|
|
873
875
|
const body: Record<string, unknown> = {};
|
|
876
|
+
if (options?.enableWorkingMemory !== undefined) {
|
|
877
|
+
body.enable_working_memory = options.enableWorkingMemory;
|
|
878
|
+
}
|
|
874
879
|
if (options?.retentionMode === "turn_budget") {
|
|
875
880
|
body.retention_mode = "turn_budget";
|
|
876
881
|
} else if (keepRecentCount > 0) {
|
package/commands/setup.ts
CHANGED
|
@@ -66,6 +66,7 @@ function readCompatRangeFromManifest(): { min: string; max: string } {
|
|
|
66
66
|
const PLUGIN_VERSION = readPluginVersion();
|
|
67
67
|
const { min: COMPATIBLE_SERVER_MIN, max: COMPATIBLE_SERVER_MAX } = readCompatRangeFromManifest();
|
|
68
68
|
const CONFIG_KEYS_TO_PRESERVE = [
|
|
69
|
+
"contextManagementMode",
|
|
69
70
|
"targetUri",
|
|
70
71
|
"headers",
|
|
71
72
|
"timeoutMs",
|
package/config.ts
CHANGED
|
@@ -42,6 +42,7 @@ export type MemoryOpenVikingConfig = {
|
|
|
42
42
|
userId?: string;
|
|
43
43
|
targetUri?: string;
|
|
44
44
|
timeoutMs?: number;
|
|
45
|
+
contextManagementMode?: "native" | "openviking";
|
|
45
46
|
autoCapture?: boolean;
|
|
46
47
|
captureMode?: "semantic" | "keyword";
|
|
47
48
|
captureMaxLength?: number;
|
|
@@ -514,6 +515,9 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
514
515
|
value = {};
|
|
515
516
|
}
|
|
516
517
|
const cfg = value as Record<string, unknown>;
|
|
518
|
+
if (cfg.contextManagementMode !== undefined && !["native", "openviking"].includes(String(cfg.contextManagementMode))) {
|
|
519
|
+
throw new Error("contextManagementMode must be native or openviking");
|
|
520
|
+
}
|
|
517
521
|
assertAllowedKeys(
|
|
518
522
|
cfg,
|
|
519
523
|
[
|
|
@@ -528,6 +532,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
528
532
|
"userId",
|
|
529
533
|
"targetUri",
|
|
530
534
|
"timeoutMs",
|
|
535
|
+
"contextManagementMode",
|
|
531
536
|
"autoCapture",
|
|
532
537
|
"captureMode",
|
|
533
538
|
"captureMaxLength",
|
|
@@ -655,6 +660,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
655
660
|
userId,
|
|
656
661
|
targetUri: typeof cfg.targetUri === "string" ? cfg.targetUri : DEFAULT_TARGET_URI,
|
|
657
662
|
timeoutMs: Math.max(1000, Math.floor(toNumber(cfg.timeoutMs, DEFAULT_TIMEOUT_MS))),
|
|
663
|
+
contextManagementMode: cfg.contextManagementMode === "openviking" ? "openviking" : "native",
|
|
658
664
|
autoCapture: cfg.autoCapture !== false,
|
|
659
665
|
captureMode: captureMode ?? DEFAULT_CAPTURE_MODE,
|
|
660
666
|
captureMaxLength: Math.max(
|
package/context-engine.ts
CHANGED
|
@@ -25,7 +25,7 @@ type ContextEngineInfo = {
|
|
|
25
25
|
id: string;
|
|
26
26
|
name: string;
|
|
27
27
|
version?: string;
|
|
28
|
-
ownsCompaction:
|
|
28
|
+
ownsCompaction: boolean;
|
|
29
29
|
/** OpenClaw >=2026.8.1: without both declarations (and commitTurn) the engine is degraded to "legacy" every turn. */
|
|
30
30
|
transcriptSemantics: {
|
|
31
31
|
currentTurnFence: "before-current-turn-entry-v1";
|
|
@@ -365,7 +365,7 @@ export function createMemoryOpenVikingContextEngine(params: {
|
|
|
365
365
|
id,
|
|
366
366
|
name,
|
|
367
367
|
version,
|
|
368
|
-
ownsCompaction:
|
|
368
|
+
ownsCompaction: cfg.contextManagementMode === "openviking",
|
|
369
369
|
transcriptSemantics: {
|
|
370
370
|
currentTurnFence: "before-current-turn-entry-v1",
|
|
371
371
|
turnAdvancementIdempotency: "atomic-idempotent-v1",
|
|
@@ -490,6 +490,7 @@ export function createMemoryOpenVikingContextEngine(params: {
|
|
|
490
490
|
async compact(compactParams): Promise<CompactResult> {
|
|
491
491
|
const tokenBudget = validTokenBudget(compactParams.tokenBudget) ?? 128_000;
|
|
492
492
|
return compactOpenVikingSession({
|
|
493
|
+
contextManagementMode: cfg.contextManagementMode,
|
|
493
494
|
sessionId: compactParams.sessionId,
|
|
494
495
|
sessionKey: resolveSessionKey(compactParams),
|
|
495
496
|
tokenBudget,
|
package/dist/client.js
CHANGED
|
@@ -414,6 +414,9 @@ export class OpenVikingClient {
|
|
|
414
414
|
retentionMode: options?.retentionMode,
|
|
415
415
|
}, options?.agentId);
|
|
416
416
|
const body = {};
|
|
417
|
+
if (options?.enableWorkingMemory !== undefined) {
|
|
418
|
+
body.enable_working_memory = options.enableWorkingMemory;
|
|
419
|
+
}
|
|
417
420
|
if (options?.retentionMode === "turn_budget") {
|
|
418
421
|
body.retention_mode = "turn_budget";
|
|
419
422
|
}
|
package/dist/commands/setup.js
CHANGED
|
@@ -56,6 +56,7 @@ function readCompatRangeFromManifest() {
|
|
|
56
56
|
const PLUGIN_VERSION = readPluginVersion();
|
|
57
57
|
const { min: COMPATIBLE_SERVER_MIN, max: COMPATIBLE_SERVER_MAX } = readCompatRangeFromManifest();
|
|
58
58
|
const CONFIG_KEYS_TO_PRESERVE = [
|
|
59
|
+
"contextManagementMode",
|
|
59
60
|
"targetUri",
|
|
60
61
|
"headers",
|
|
61
62
|
"timeoutMs",
|
package/dist/config.js
CHANGED
|
@@ -328,6 +328,9 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
328
328
|
value = {};
|
|
329
329
|
}
|
|
330
330
|
const cfg = value;
|
|
331
|
+
if (cfg.contextManagementMode !== undefined && !["native", "openviking"].includes(String(cfg.contextManagementMode))) {
|
|
332
|
+
throw new Error("contextManagementMode must be native or openviking");
|
|
333
|
+
}
|
|
331
334
|
assertAllowedKeys(cfg, [
|
|
332
335
|
"mode",
|
|
333
336
|
"baseUrl",
|
|
@@ -340,6 +343,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
340
343
|
"userId",
|
|
341
344
|
"targetUri",
|
|
342
345
|
"timeoutMs",
|
|
346
|
+
"contextManagementMode",
|
|
343
347
|
"autoCapture",
|
|
344
348
|
"captureMode",
|
|
345
349
|
"captureMaxLength",
|
|
@@ -436,6 +440,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
436
440
|
userId,
|
|
437
441
|
targetUri: typeof cfg.targetUri === "string" ? cfg.targetUri : DEFAULT_TARGET_URI,
|
|
438
442
|
timeoutMs: Math.max(1000, Math.floor(toNumber(cfg.timeoutMs, DEFAULT_TIMEOUT_MS))),
|
|
443
|
+
contextManagementMode: cfg.contextManagementMode === "openviking" ? "openviking" : "native",
|
|
439
444
|
autoCapture: cfg.autoCapture !== false,
|
|
440
445
|
captureMode: captureMode ?? DEFAULT_CAPTURE_MODE,
|
|
441
446
|
captureMaxLength: Math.max(200, Math.min(200_000, Math.floor(toNumber(cfg.captureMaxLength, DEFAULT_CAPTURE_MAX_LENGTH)))),
|
package/dist/context-engine.js
CHANGED
|
@@ -191,7 +191,7 @@ export function createMemoryOpenVikingContextEngine(params) {
|
|
|
191
191
|
id,
|
|
192
192
|
name,
|
|
193
193
|
version,
|
|
194
|
-
ownsCompaction:
|
|
194
|
+
ownsCompaction: cfg.contextManagementMode === "openviking",
|
|
195
195
|
transcriptSemantics: {
|
|
196
196
|
currentTurnFence: "before-current-turn-entry-v1",
|
|
197
197
|
turnAdvancementIdempotency: "atomic-idempotent-v1",
|
|
@@ -308,6 +308,7 @@ export function createMemoryOpenVikingContextEngine(params) {
|
|
|
308
308
|
async compact(compactParams) {
|
|
309
309
|
const tokenBudget = validTokenBudget(compactParams.tokenBudget) ?? 128_000;
|
|
310
310
|
return compactOpenVikingSession({
|
|
311
|
+
contextManagementMode: cfg.contextManagementMode,
|
|
311
312
|
sessionId: compactParams.sessionId,
|
|
312
313
|
sessionKey: resolveSessionKey(compactParams),
|
|
313
314
|
tokenBudget,
|
|
@@ -95,13 +95,31 @@ export function registerOpenVikingMemoryTools(deps) {
|
|
|
95
95
|
};
|
|
96
96
|
}
|
|
97
97
|
if (memoriesCount === 0) {
|
|
98
|
-
deps.logger.warn(`openviking: memory_store committed but 0 memories extracted (sessionId=${sessionId})
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
deps.logger.warn(`openviking: memory_store committed but 0 memories extracted (sessionId=${sessionId}), ` +
|
|
99
|
+
`trace_id=${commitResult.trace_id ?? "none"}. ` +
|
|
100
|
+
"No memory was created or updated. Check memory.extraction_enabled, VLM configuration/API keys, or whether the content is already stored.");
|
|
101
|
+
return {
|
|
102
|
+
content: [{
|
|
103
|
+
type: "text",
|
|
104
|
+
text: `Memory extraction completed for session ${sessionId}, but created or updated no memory. ` +
|
|
105
|
+
"The content may already be stored, memory extraction may be disabled, or the extractor found nothing new to store. " +
|
|
106
|
+
"Tell the user no new memory was created." +
|
|
107
|
+
(commitResult.trace_id ? ` (trace_id=${commitResult.trace_id})` : ""),
|
|
108
|
+
}],
|
|
109
|
+
details: {
|
|
110
|
+
action: "failed",
|
|
111
|
+
sessionId,
|
|
112
|
+
status: commitResult.status,
|
|
113
|
+
error: "no_memories_extracted",
|
|
114
|
+
memoriesCount,
|
|
115
|
+
archived: commitResult.archived ?? false,
|
|
116
|
+
traceId: commitResult.trace_id,
|
|
117
|
+
usedTempSession,
|
|
118
|
+
},
|
|
119
|
+
};
|
|
104
120
|
}
|
|
121
|
+
deps.logger.info?.(`openviking: memory_store committed, memories=${memoriesCount}, ` +
|
|
122
|
+
`trace_id=${commitResult.trace_id ?? "none"}`);
|
|
105
123
|
return {
|
|
106
124
|
content: [
|
|
107
125
|
{
|
|
@@ -344,12 +344,23 @@ async function assembleSessionContext(params) {
|
|
|
344
344
|
});
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
|
+
if (cfg.contextManagementMode !== "openviking") {
|
|
348
|
+
return assemblePassthrough({ diag, ovSessionId, reason: "native_context", liveMessages: messages, originalTokens });
|
|
349
|
+
}
|
|
347
350
|
try {
|
|
348
351
|
const client = await getClient();
|
|
349
352
|
const ctx = await client.getSessionContext(ovSessionId, tokenBudget);
|
|
350
353
|
const preAbstracts = ctx?.pre_archive_abstracts ?? [];
|
|
351
354
|
const hasArchives = !!ctx?.latest_archive_overview || preAbstracts.length > 0;
|
|
352
355
|
const activeCount = ctx?.messages?.length ?? 0;
|
|
356
|
+
// A completed WM-off archive can leave a non-empty active tail. That tail
|
|
357
|
+
// alone cannot replace the host's earlier history in explicit OV mode.
|
|
358
|
+
if (!hasArchives && (ctx?.stats?.totalArchives ?? 0) > 0) {
|
|
359
|
+
logger.warn?.("openviking: archived context has no summary; keeping native history");
|
|
360
|
+
return assemblePassthrough({
|
|
361
|
+
diag, ovSessionId, reason: "archive_summary_missing", liveMessages: messages, originalTokens,
|
|
362
|
+
});
|
|
363
|
+
}
|
|
353
364
|
if (!ctx || (!hasArchives && activeCount === 0)) {
|
|
354
365
|
return assemblePassthrough({
|
|
355
366
|
diag,
|
|
@@ -658,6 +669,7 @@ export async function afterTurnOpenVikingSession({ throwOnError = false, session
|
|
|
658
669
|
}
|
|
659
670
|
const commitResult = await client.commitSession(ovSessionId, {
|
|
660
671
|
wait: false,
|
|
672
|
+
...(cfg.contextManagementMode === "openviking" ? { enableWorkingMemory: true } : {}),
|
|
661
673
|
...(cfg.commitRetentionMode === "turn_budget"
|
|
662
674
|
? { retentionMode: "turn_budget" }
|
|
663
675
|
: { keepRecentCount: cfg.commitKeepRecentCount }),
|
|
@@ -666,6 +678,7 @@ export async function afterTurnOpenVikingSession({ throwOnError = false, session
|
|
|
666
678
|
`status=${commitResult.status}, archived=${commitResult.archived ?? false}, ` +
|
|
667
679
|
`task_id=${commitResult.task_id ?? "none"}, trace_id=${commitResult.trace_id ?? "none"}`);
|
|
668
680
|
diag("afterTurn_commit", ovSessionId, {
|
|
681
|
+
effectiveEnableWorkingMemory: commitResult.effective_enable_working_memory,
|
|
669
682
|
pendingTokens,
|
|
670
683
|
commitTokenThreshold,
|
|
671
684
|
commitTokenThresholdRatio: cfg.commitTokenThresholdRatio,
|
|
@@ -715,7 +728,7 @@ function compactFailureResult(reason, tokensBefore, details) {
|
|
|
715
728
|
},
|
|
716
729
|
};
|
|
717
730
|
}
|
|
718
|
-
export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBudget, currentTokenCount, force, compactionTarget, customInstructions, getClient, logger, resolveAgentId, isBypassedSession, runtimeCompact, diag, }) {
|
|
731
|
+
export async function compactOpenVikingSession({ contextManagementMode = "native", sessionId, sessionKey, tokenBudget, currentTokenCount, force, compactionTarget, customInstructions, getClient, logger, resolveAgentId, isBypassedSession, runtimeCompact, diag, }) {
|
|
719
732
|
const ovSessionId = openClawSessionToOvStorageId(sessionId, sessionKey);
|
|
720
733
|
diag("compact_entry", ovSessionId, {
|
|
721
734
|
tokenBudget,
|
|
@@ -749,6 +762,9 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
|
|
|
749
762
|
reason: "session_bypassed",
|
|
750
763
|
};
|
|
751
764
|
}
|
|
765
|
+
if (contextManagementMode === "native") {
|
|
766
|
+
return await runtimeCompact?.() ?? compactFailureResult("native_compaction_unavailable", validTokenCount(currentTokenCount) ?? -1, { message: "Upgrade OpenClaw to a version with runtime compaction delegation." });
|
|
767
|
+
}
|
|
752
768
|
const client = await getClient();
|
|
753
769
|
const agentId = resolveAgentId(sessionId, sessionKey, ovSessionId);
|
|
754
770
|
const tokensBeforeOriginal = validTokenCount(currentTokenCount);
|
|
@@ -771,6 +787,7 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
|
|
|
771
787
|
const commitResult = await client.commitSession(ovSessionId, {
|
|
772
788
|
wait: true,
|
|
773
789
|
keepRecentCount: 0,
|
|
790
|
+
enableWorkingMemory: true,
|
|
774
791
|
});
|
|
775
792
|
const memCount = totalExtractedMemories(commitResult.memories_extracted);
|
|
776
793
|
if (commitResult.status === "failed") {
|
|
@@ -828,6 +845,9 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
|
|
|
828
845
|
},
|
|
829
846
|
};
|
|
830
847
|
}
|
|
848
|
+
if (commitResult.effective_enable_working_memory !== true) {
|
|
849
|
+
return await runtimeCompact?.() ?? compactFailureResult("working_memory_disabled", tokensBefore, { commit: commitResult });
|
|
850
|
+
}
|
|
831
851
|
let summary = "";
|
|
832
852
|
const firstKeptEntryId = commitResult.archive_uri?.split("/").pop() ?? "";
|
|
833
853
|
let tokensAfter;
|
|
@@ -875,6 +895,9 @@ export async function compactOpenVikingSession({ sessionId, sessionKey, tokenBud
|
|
|
875
895
|
logger.info(`openviking: compact tokens session=${ovSessionId}, ` +
|
|
876
896
|
`tokensBefore=${tokensBefore}, tokensAfter=${tokensAfter ?? "unknown"}, ` +
|
|
877
897
|
`latestArchiveId=${firstKeptEntryId || "none"}`);
|
|
898
|
+
if (!summary) {
|
|
899
|
+
return await runtimeCompact?.() ?? compactFailureResult("archive_summary_missing", tokensBefore, { commit: commitResult });
|
|
900
|
+
}
|
|
878
901
|
diag("compact_result", ovSessionId, {
|
|
879
902
|
ok: true,
|
|
880
903
|
compacted: true,
|
package/install-manifest.json
CHANGED
package/openclaw.plugin.json
CHANGED
|
@@ -353,6 +353,12 @@
|
|
|
353
353
|
"timeoutMs": {
|
|
354
354
|
"type": "number"
|
|
355
355
|
},
|
|
356
|
+
"contextManagementMode": {
|
|
357
|
+
"type": "string",
|
|
358
|
+
"enum": ["native", "openviking"],
|
|
359
|
+
"default": "native",
|
|
360
|
+
"description": "Use host history and compaction; openviking explicitly enables Working Memory context management."
|
|
361
|
+
},
|
|
356
362
|
"autoCapture": {
|
|
357
363
|
"type": "boolean"
|
|
358
364
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openviking/openclaw-plugin",
|
|
3
|
-
"version": "2026.10.
|
|
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",
|
|
@@ -176,15 +176,34 @@ export function registerOpenVikingMemoryTools(deps: OpenVikingMemoryToolsDeps):
|
|
|
176
176
|
}
|
|
177
177
|
if (memoriesCount === 0) {
|
|
178
178
|
deps.logger.warn(
|
|
179
|
-
`openviking: memory_store committed but 0 memories extracted (sessionId=${sessionId})
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
} else {
|
|
183
|
-
deps.logger.info?.(
|
|
184
|
-
`openviking: memory_store committed, memories=${memoriesCount}, ` +
|
|
185
|
-
`trace_id=${commitResult.trace_id ?? "none"}`,
|
|
179
|
+
`openviking: memory_store committed but 0 memories extracted (sessionId=${sessionId}), ` +
|
|
180
|
+
`trace_id=${commitResult.trace_id ?? "none"}. ` +
|
|
181
|
+
"No memory was created or updated. Check memory.extraction_enabled, VLM configuration/API keys, or whether the content is already stored.",
|
|
186
182
|
);
|
|
183
|
+
return {
|
|
184
|
+
content: [{
|
|
185
|
+
type: "text",
|
|
186
|
+
text: `Memory extraction completed for session ${sessionId}, but created or updated no memory. ` +
|
|
187
|
+
"The content may already be stored, memory extraction may be disabled, or the extractor found nothing new to store. " +
|
|
188
|
+
"Tell the user no new memory was created." +
|
|
189
|
+
(commitResult.trace_id ? ` (trace_id=${commitResult.trace_id})` : ""),
|
|
190
|
+
}],
|
|
191
|
+
details: {
|
|
192
|
+
action: "failed",
|
|
193
|
+
sessionId,
|
|
194
|
+
status: commitResult.status,
|
|
195
|
+
error: "no_memories_extracted",
|
|
196
|
+
memoriesCount,
|
|
197
|
+
archived: commitResult.archived ?? false,
|
|
198
|
+
traceId: commitResult.trace_id,
|
|
199
|
+
usedTempSession,
|
|
200
|
+
},
|
|
201
|
+
};
|
|
187
202
|
}
|
|
203
|
+
deps.logger.info?.(
|
|
204
|
+
`openviking: memory_store committed, memories=${memoriesCount}, ` +
|
|
205
|
+
`trace_id=${commitResult.trace_id ?? "none"}`,
|
|
206
|
+
);
|
|
188
207
|
return {
|
|
189
208
|
content: [
|
|
190
209
|
{
|
|
@@ -107,6 +107,7 @@ export type AssembleOpenVikingSessionParams = {
|
|
|
107
107
|
type CompactClient = Pick<OpenVikingClient, "commitSession" | "getSessionContext">;
|
|
108
108
|
|
|
109
109
|
export type CompactOpenVikingSessionParams = {
|
|
110
|
+
contextManagementMode?: "native" | "openviking";
|
|
110
111
|
sessionId: string;
|
|
111
112
|
sessionKey?: string;
|
|
112
113
|
tokenBudget: number;
|
|
@@ -138,6 +139,7 @@ export type AfterTurnOpenVikingSessionParams = {
|
|
|
138
139
|
runtimeContext?: Record<string, unknown>;
|
|
139
140
|
cfg: {
|
|
140
141
|
autoCapture: boolean;
|
|
142
|
+
contextManagementMode?: "native" | "openviking";
|
|
141
143
|
commitTokenThresholdRatio: number;
|
|
142
144
|
commitKeepRecentCount: number;
|
|
143
145
|
commitRetentionMode?: "message_count" | "turn_budget";
|
|
@@ -610,6 +612,10 @@ async function assembleSessionContext(params: AssembleOpenVikingSessionParams):
|
|
|
610
612
|
}
|
|
611
613
|
}
|
|
612
614
|
|
|
615
|
+
if (cfg.contextManagementMode !== "openviking") {
|
|
616
|
+
return assemblePassthrough({ diag, ovSessionId, reason: "native_context", liveMessages: messages, originalTokens });
|
|
617
|
+
}
|
|
618
|
+
|
|
613
619
|
try {
|
|
614
620
|
const client = await getClient();
|
|
615
621
|
const ctx = await client.getSessionContext(ovSessionId, tokenBudget);
|
|
@@ -618,6 +624,15 @@ async function assembleSessionContext(params: AssembleOpenVikingSessionParams):
|
|
|
618
624
|
const hasArchives = !!ctx?.latest_archive_overview || preAbstracts.length > 0;
|
|
619
625
|
const activeCount = ctx?.messages?.length ?? 0;
|
|
620
626
|
|
|
627
|
+
// A completed WM-off archive can leave a non-empty active tail. That tail
|
|
628
|
+
// alone cannot replace the host's earlier history in explicit OV mode.
|
|
629
|
+
if (!hasArchives && (ctx?.stats?.totalArchives ?? 0) > 0) {
|
|
630
|
+
logger.warn?.("openviking: archived context has no summary; keeping native history");
|
|
631
|
+
return assemblePassthrough({
|
|
632
|
+
diag, ovSessionId, reason: "archive_summary_missing", liveMessages: messages, originalTokens,
|
|
633
|
+
});
|
|
634
|
+
}
|
|
635
|
+
|
|
621
636
|
if (!ctx || (!hasArchives && activeCount === 0)) {
|
|
622
637
|
return assemblePassthrough({
|
|
623
638
|
diag,
|
|
@@ -989,6 +1004,7 @@ export async function afterTurnOpenVikingSession({
|
|
|
989
1004
|
|
|
990
1005
|
const commitResult = await client.commitSession(ovSessionId, {
|
|
991
1006
|
wait: false,
|
|
1007
|
+
...(cfg.contextManagementMode === "openviking" ? { enableWorkingMemory: true } : {}),
|
|
992
1008
|
...(cfg.commitRetentionMode === "turn_budget"
|
|
993
1009
|
? { retentionMode: "turn_budget" as const }
|
|
994
1010
|
: { keepRecentCount: cfg.commitKeepRecentCount }),
|
|
@@ -1000,6 +1016,7 @@ export async function afterTurnOpenVikingSession({
|
|
|
1000
1016
|
);
|
|
1001
1017
|
|
|
1002
1018
|
diag("afterTurn_commit", ovSessionId, {
|
|
1019
|
+
effectiveEnableWorkingMemory: commitResult.effective_enable_working_memory,
|
|
1003
1020
|
pendingTokens,
|
|
1004
1021
|
commitTokenThreshold,
|
|
1005
1022
|
commitTokenThresholdRatio: cfg.commitTokenThresholdRatio,
|
|
@@ -1058,6 +1075,7 @@ function compactFailureResult(
|
|
|
1058
1075
|
}
|
|
1059
1076
|
|
|
1060
1077
|
export async function compactOpenVikingSession({
|
|
1078
|
+
contextManagementMode = "native",
|
|
1061
1079
|
sessionId,
|
|
1062
1080
|
sessionKey,
|
|
1063
1081
|
tokenBudget,
|
|
@@ -1107,6 +1125,13 @@ export async function compactOpenVikingSession({
|
|
|
1107
1125
|
};
|
|
1108
1126
|
}
|
|
1109
1127
|
|
|
1128
|
+
if (contextManagementMode === "native") {
|
|
1129
|
+
return await runtimeCompact?.() ?? compactFailureResult(
|
|
1130
|
+
"native_compaction_unavailable", validTokenCount(currentTokenCount) ?? -1,
|
|
1131
|
+
{ message: "Upgrade OpenClaw to a version with runtime compaction delegation." },
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1110
1135
|
const client = await getClient();
|
|
1111
1136
|
const agentId = resolveAgentId(sessionId, sessionKey, ovSessionId);
|
|
1112
1137
|
const tokensBeforeOriginal = validTokenCount(currentTokenCount);
|
|
@@ -1134,6 +1159,7 @@ export async function compactOpenVikingSession({
|
|
|
1134
1159
|
const commitResult = await client.commitSession(ovSessionId, {
|
|
1135
1160
|
wait: true,
|
|
1136
1161
|
keepRecentCount: 0,
|
|
1162
|
+
enableWorkingMemory: true,
|
|
1137
1163
|
});
|
|
1138
1164
|
const memCount = totalExtractedMemories(commitResult.memories_extracted);
|
|
1139
1165
|
|
|
@@ -1204,6 +1230,10 @@ export async function compactOpenVikingSession({
|
|
|
1204
1230
|
};
|
|
1205
1231
|
}
|
|
1206
1232
|
|
|
1233
|
+
if (commitResult.effective_enable_working_memory !== true) {
|
|
1234
|
+
return await runtimeCompact?.() ?? compactFailureResult("working_memory_disabled", tokensBefore, { commit: commitResult });
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1207
1237
|
let summary = "";
|
|
1208
1238
|
const firstKeptEntryId = commitResult.archive_uri?.split("/").pop() ?? "";
|
|
1209
1239
|
let tokensAfter: number | undefined;
|
|
@@ -1264,6 +1294,10 @@ export async function compactOpenVikingSession({
|
|
|
1264
1294
|
`latestArchiveId=${firstKeptEntryId || "none"}`,
|
|
1265
1295
|
);
|
|
1266
1296
|
|
|
1297
|
+
if (!summary) {
|
|
1298
|
+
return await runtimeCompact?.() ?? compactFailureResult("archive_summary_missing", tokensBefore, { commit: commitResult });
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1267
1301
|
diag("compact_result", ovSessionId, {
|
|
1268
1302
|
ok: true,
|
|
1269
1303
|
compacted: true,
|
|
@@ -30,7 +30,7 @@ Choose the registered names that match the current runtime:
|
|
|
30
30
|
| Runtime | Search | Read |
|
|
31
31
|
| --- | --- | --- |
|
|
32
32
|
| OpenViking MCP, Codex, Claude Code | `find` or `search` | `read` |
|
|
33
|
-
| OpenCode | `openviking_find` or `openviking_search` | `openviking_read` |
|
|
33
|
+
| OpenCode, pi | `openviking_find` or `openviking_search` | `openviking_read` |
|
|
34
34
|
| OpenClaw | `ov_search` | `ov_read` or `ov_multi_read` |
|
|
35
35
|
|
|
36
36
|
The host may display MCP names with a namespace such as
|