@openviking/openclaw-plugin 2026.5.26 → 2026.6.2
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 +355 -355
- package/INSTALL-ZH.md +345 -345
- package/INSTALL.md +362 -362
- package/README.md +354 -338
- package/auto-recall.ts +287 -257
- package/client.ts +939 -939
- package/commands/setup.ts +1002 -1002
- package/config.ts +476 -476
- package/context-engine.ts +1739 -1737
- package/dist/auto-recall.js +27 -7
- package/dist/client.js +2 -2
- package/dist/context-engine.js +4 -8
- package/dist/index.js +21 -2
- package/dist/process-manager.js +5 -17
- package/dist/token-estimator.js +51 -0
- package/index.ts +2010 -1985
- package/install-manifest.json +48 -47
- package/memory-ranking.ts +267 -267
- package/openclaw.plugin.json +335 -335
- package/package.json +76 -76
- package/process-manager.ts +41 -45
- package/runtime-utils.ts +5 -5
- package/session-transcript-repair.ts +530 -530
- package/skills/install-openviking-memory/SKILL.md +679 -665
- package/text-utils.ts +507 -507
- package/token-estimator.ts +65 -0
- package/tool-call-id.ts +331 -331
package/dist/auto-recall.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { pickMemoriesForInjection, postProcessMemories, summarizeInjectionMemories, toJsonLog, } from "./memory-ranking.js";
|
|
2
2
|
import { quickRecallPrecheck, withTimeout } from "./process-manager.js";
|
|
3
3
|
import { sanitizeUserTextForCapture } from "./text-utils.js";
|
|
4
|
+
import { estimateTextTokens } from "./token-estimator.js";
|
|
4
5
|
const AUTO_RECALL_TIMEOUT_MS = 5_000;
|
|
5
6
|
const RECALL_QUERY_MAX_CHARS = 4_000;
|
|
6
7
|
export const AUTO_RECALL_SOURCE_MARKER = "Source: openviking-auto-recall";
|
|
@@ -25,11 +26,29 @@ export function prepareRecallQuery(rawText) {
|
|
|
25
26
|
finalChars: query.length,
|
|
26
27
|
};
|
|
27
28
|
}
|
|
28
|
-
/** Estimate token count using
|
|
29
|
+
/** Estimate token count using the shared CJK-aware fallback for diagnostics. */
|
|
29
30
|
export function estimateTokenCount(text) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
return estimateTextTokens(text);
|
|
32
|
+
}
|
|
33
|
+
function memoryCategory(item) {
|
|
34
|
+
return item.category?.trim() || "memory";
|
|
35
|
+
}
|
|
36
|
+
function indentContent(content) {
|
|
37
|
+
return content
|
|
38
|
+
.split("\n")
|
|
39
|
+
.map((line) => ` ${line}`)
|
|
40
|
+
.join("\n");
|
|
41
|
+
}
|
|
42
|
+
function formatMemoryLine(item, content, options) {
|
|
43
|
+
const category = memoryCategory(item);
|
|
44
|
+
if (!options.includeUri) {
|
|
45
|
+
return `- [${category}] ${content}`;
|
|
46
|
+
}
|
|
47
|
+
return [
|
|
48
|
+
`- [${category}]`,
|
|
49
|
+
` <uri>${item.uri}</uri>`,
|
|
50
|
+
indentContent(content),
|
|
51
|
+
].join("\n");
|
|
33
52
|
}
|
|
34
53
|
async function resolveMemoryContent(item, readFn, options) {
|
|
35
54
|
let content;
|
|
@@ -57,7 +76,7 @@ export async function buildMemoryLines(memories, readFn, options) {
|
|
|
57
76
|
const lines = [];
|
|
58
77
|
for (const item of memories) {
|
|
59
78
|
const content = await resolveMemoryContent(item, readFn, options);
|
|
60
|
-
lines.push(
|
|
79
|
+
lines.push(formatMemoryLine(item, content, options));
|
|
61
80
|
}
|
|
62
81
|
return lines;
|
|
63
82
|
}
|
|
@@ -78,7 +97,7 @@ export async function buildMemoryLinesWithBudget(memories, readFn, options) {
|
|
|
78
97
|
break;
|
|
79
98
|
}
|
|
80
99
|
const content = await resolveMemoryContent(item, readFn, options);
|
|
81
|
-
const line =
|
|
100
|
+
const line = formatMemoryLine(item, content, options);
|
|
82
101
|
const separatorChars = lines.length > 0 ? 1 : 0;
|
|
83
102
|
const projectedChars = totalChars + separatorChars + line.length;
|
|
84
103
|
if (projectedChars > charBudget) {
|
|
@@ -105,7 +124,7 @@ export async function buildAutoRecallContext(params) {
|
|
|
105
124
|
if (!cfg.autoRecall || queryText.length < 5) {
|
|
106
125
|
return { memoryCount: 0, estimatedTokens: 0 };
|
|
107
126
|
}
|
|
108
|
-
const precheck = await quickRecallPrecheck(
|
|
127
|
+
const precheck = await quickRecallPrecheck(client, agentId);
|
|
109
128
|
if (!precheck.ok) {
|
|
110
129
|
verbose?.(`openviking: skipping auto-recall because precheck failed (${precheck.reason})`);
|
|
111
130
|
return { memoryCount: 0, estimatedTokens: 0 };
|
|
@@ -154,6 +173,7 @@ export async function buildAutoRecallContext(params) {
|
|
|
154
173
|
const { lines: memoryLines, estimatedTokens } = await buildMemoryLinesWithBudget(memories, (uri) => client.read(uri, agentId), {
|
|
155
174
|
recallPreferAbstract: cfg.recallPreferAbstract,
|
|
156
175
|
recallMaxInjectedChars: cfg.recallMaxInjectedChars,
|
|
176
|
+
includeUri: true,
|
|
157
177
|
});
|
|
158
178
|
if (memoryLines.length === 0) {
|
|
159
179
|
verbose?.(`openviking: skipping auto-recall injection; no complete memories fit maxInjectedChars=${cfg.recallMaxInjectedChars}`);
|
package/dist/client.js
CHANGED
|
@@ -155,8 +155,8 @@ export class OpenVikingClient {
|
|
|
155
155
|
clearTimeout(timer);
|
|
156
156
|
}
|
|
157
157
|
}
|
|
158
|
-
async healthCheck() {
|
|
159
|
-
await this.request("/health");
|
|
158
|
+
async healthCheck(agentId, requestTimeoutMs) {
|
|
159
|
+
await this.request("/health", {}, agentId, requestTimeoutMs);
|
|
160
160
|
}
|
|
161
161
|
async getRuntimeIdentity(agentId) {
|
|
162
162
|
const effectiveAgentId = this.resolveEffectiveAgentId(agentId);
|
package/dist/context-engine.js
CHANGED
|
@@ -4,6 +4,7 @@ import { AUTO_RECALL_SOURCE_MARKER, buildAutoRecallContext, prepareRecallQuery,
|
|
|
4
4
|
import { compileSessionPatterns, extractNewTurnMessages, shouldBypassSession, } from "./text-utils.js";
|
|
5
5
|
import { toJsonLog, } from "./memory-ranking.js";
|
|
6
6
|
import { sanitizeToolUseResultPairing } from "./session-transcript-repair.js";
|
|
7
|
+
import { estimateAgentMessageTokens, estimateAgentMessagesTokens, estimateTextTokens, } from "./token-estimator.js";
|
|
7
8
|
export function toRoleId(senderId) {
|
|
8
9
|
if (!senderId) {
|
|
9
10
|
return undefined;
|
|
@@ -30,15 +31,10 @@ function allocateContextBudget(totalBudget, instructionTokens = 0) {
|
|
|
30
31
|
return { archiveMemory, sessionContext, reserved };
|
|
31
32
|
}
|
|
32
33
|
function roughEstimate(messages) {
|
|
33
|
-
return
|
|
34
|
+
return estimateAgentMessagesTokens(messages);
|
|
34
35
|
}
|
|
35
36
|
function msgTokenEstimate(msg) {
|
|
36
|
-
|
|
37
|
-
if (typeof raw === "string")
|
|
38
|
-
return Math.ceil(raw.length / 4);
|
|
39
|
-
if (Array.isArray(raw))
|
|
40
|
-
return Math.ceil(JSON.stringify(raw).length / 4);
|
|
41
|
-
return 1;
|
|
37
|
+
return estimateAgentMessageTokens(msg);
|
|
42
38
|
}
|
|
43
39
|
function normalizeTimestamp(value) {
|
|
44
40
|
if (typeof value === "number" && Number.isFinite(value)) {
|
|
@@ -503,7 +499,7 @@ function buildSystemPromptAddition() {
|
|
|
503
499
|
}
|
|
504
500
|
function buildInstructionPrompt() {
|
|
505
501
|
const text = buildSystemPromptAddition();
|
|
506
|
-
return { text, tokens:
|
|
502
|
+
return { text, tokens: estimateTextTokens(text) };
|
|
507
503
|
}
|
|
508
504
|
function buildArchiveMemory(archiveOverview, _preAbstracts, _budget) {
|
|
509
505
|
const messages = [];
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ import { clampScore, postProcessMemories, pickMemoriesForInjection, } from "./me
|
|
|
8
8
|
import { createMemoryOpenVikingContextEngine, openClawSessionToOvStorageId, openClawSessionRefToOvStorageId, } from "./context-engine.js";
|
|
9
9
|
import { buildMemoryLines, buildMemoryLinesWithBudget, estimateTokenCount, prepareRecallQuery, } from "./auto-recall.js";
|
|
10
10
|
export { buildMemoryLines, buildMemoryLinesWithBudget, estimateTokenCount, prepareRecallQuery, };
|
|
11
|
+
export { estimateAgentMessageTokens, estimateAgentMessagesTokens, estimateSerializedTokens, estimateTextTokens, } from "./token-estimator.js";
|
|
11
12
|
function parseToolResultRef(value) {
|
|
12
13
|
const raw = typeof value === "string" ? value.trim() : "";
|
|
13
14
|
if (!raw) {
|
|
@@ -848,7 +849,7 @@ const contextEnginePlugin = {
|
|
|
848
849
|
api.registerTool((ctx) => ({
|
|
849
850
|
name: "memory_store",
|
|
850
851
|
label: "Memory Store (OpenViking)",
|
|
851
|
-
description: "Store text in OpenViking memory pipeline by writing to a session and running memory extraction.",
|
|
852
|
+
description: "Store text in OpenViking memory pipeline by writing to a session and running memory extraction. Use when the user explicitly asks to remember, save, or store an important long-term fact, preference, project, or decision; automatic capture is threshold/commit dependent.",
|
|
852
853
|
parameters: Type.Object({
|
|
853
854
|
text: Type.String({ description: "Information to store as memory source text" }),
|
|
854
855
|
role: Type.Optional(Type.String({ description: "Session role, default user" })),
|
|
@@ -914,7 +915,25 @@ const contextEnginePlugin = {
|
|
|
914
915
|
}
|
|
915
916
|
if (memoriesCount === 0) {
|
|
916
917
|
api.logger.warn(`openviking: memory_store committed but 0 memories extracted (sessionId=${sessionId}). ` +
|
|
917
|
-
"
|
|
918
|
+
"No OpenViking-managed long-term memory was created. Check memory.extraction_enabled, VLM configuration/API keys, or whether the text was judged not durable.");
|
|
919
|
+
return {
|
|
920
|
+
content: [
|
|
921
|
+
{
|
|
922
|
+
type: "text",
|
|
923
|
+
text: `Memory extraction completed for session ${sessionId}, but produced 0 memories. ` +
|
|
924
|
+
"No OpenViking-managed long-term memory was stored. Check memory.extraction_enabled, VLM configuration/API keys, or whether the text is durable enough to remember.",
|
|
925
|
+
},
|
|
926
|
+
],
|
|
927
|
+
details: {
|
|
928
|
+
action: "failed",
|
|
929
|
+
sessionId,
|
|
930
|
+
status: commitResult.status,
|
|
931
|
+
error: "no_memories_extracted",
|
|
932
|
+
memoriesCount,
|
|
933
|
+
archived: commitResult.archived ?? false,
|
|
934
|
+
usedTempSession,
|
|
935
|
+
},
|
|
936
|
+
};
|
|
918
937
|
}
|
|
919
938
|
else {
|
|
920
939
|
api.logger.info?.(`openviking: memory_store committed, memories=${memoriesCount}`);
|
package/dist/process-manager.js
CHANGED
|
@@ -10,29 +10,17 @@ export function withTimeout(promise, timeoutMs, timeoutMessage) {
|
|
|
10
10
|
});
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
-
export async function quickHealthCheck(
|
|
14
|
-
const controller = new AbortController();
|
|
15
|
-
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
13
|
+
export async function quickHealthCheck(client, agentId, timeoutMs) {
|
|
16
14
|
try {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
signal: controller.signal,
|
|
20
|
-
});
|
|
21
|
-
if (!response.ok) {
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
const body = (await response.json().catch(() => ({})));
|
|
25
|
-
return body.status === "ok";
|
|
15
|
+
await client.healthCheck(agentId, timeoutMs);
|
|
16
|
+
return true;
|
|
26
17
|
}
|
|
27
18
|
catch {
|
|
28
19
|
return false;
|
|
29
20
|
}
|
|
30
|
-
finally {
|
|
31
|
-
clearTimeout(timer);
|
|
32
|
-
}
|
|
33
21
|
}
|
|
34
|
-
export async function quickRecallPrecheck(
|
|
35
|
-
const healthOk = await quickHealthCheck(
|
|
22
|
+
export async function quickRecallPrecheck(client, agentId) {
|
|
23
|
+
const healthOk = await quickHealthCheck(client, agentId, 500);
|
|
36
24
|
if (healthOk) {
|
|
37
25
|
return { ok: true };
|
|
38
26
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
function isCjkCodePoint(codePoint) {
|
|
2
|
+
return ((codePoint >= 0x3400 && codePoint <= 0x4dbf) ||
|
|
3
|
+
(codePoint >= 0x4e00 && codePoint <= 0x9fff) ||
|
|
4
|
+
(codePoint >= 0xf900 && codePoint <= 0xfaff) ||
|
|
5
|
+
(codePoint >= 0x20000 && codePoint <= 0x2ebef) ||
|
|
6
|
+
(codePoint >= 0x3040 && codePoint <= 0x30ff) ||
|
|
7
|
+
(codePoint >= 0x31f0 && codePoint <= 0x31ff) ||
|
|
8
|
+
(codePoint >= 0xac00 && codePoint <= 0xd7af) ||
|
|
9
|
+
(codePoint >= 0x1100 && codePoint <= 0x11ff) ||
|
|
10
|
+
(codePoint >= 0x3130 && codePoint <= 0x318f) ||
|
|
11
|
+
(codePoint >= 0xff00 && codePoint <= 0xffef) ||
|
|
12
|
+
(codePoint >= 0x3000 && codePoint <= 0x303f));
|
|
13
|
+
}
|
|
14
|
+
function codePointWeight(codePoint) {
|
|
15
|
+
if (isCjkCodePoint(codePoint)) {
|
|
16
|
+
return 1.5;
|
|
17
|
+
}
|
|
18
|
+
if (codePoint > 0xffff) {
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
return 0.25;
|
|
22
|
+
}
|
|
23
|
+
export function estimateTextTokens(text) {
|
|
24
|
+
if (!text) {
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
let weightedTokens = 0;
|
|
28
|
+
for (const char of text) {
|
|
29
|
+
weightedTokens += codePointWeight(char.codePointAt(0) ?? 0);
|
|
30
|
+
}
|
|
31
|
+
return Math.ceil(weightedTokens);
|
|
32
|
+
}
|
|
33
|
+
export function estimateSerializedTokens(value) {
|
|
34
|
+
if (value === null || value === undefined) {
|
|
35
|
+
return 0;
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === "string") {
|
|
38
|
+
return estimateTextTokens(value);
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
|
|
41
|
+
return estimateTextTokens(String(value));
|
|
42
|
+
}
|
|
43
|
+
const serialized = JSON.stringify(value);
|
|
44
|
+
return estimateTextTokens(serialized ?? "");
|
|
45
|
+
}
|
|
46
|
+
export function estimateAgentMessageTokens(message) {
|
|
47
|
+
return estimateSerializedTokens(message);
|
|
48
|
+
}
|
|
49
|
+
export function estimateAgentMessagesTokens(messages) {
|
|
50
|
+
return estimateSerializedTokens(messages);
|
|
51
|
+
}
|