@openviking/openclaw-plugin 2026.5.8
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 -0
- package/INSTALL-ZH.md +345 -0
- package/INSTALL.md +362 -0
- package/README.md +315 -0
- package/auto-recall.ts +257 -0
- package/client.ts +828 -0
- package/commands/setup.ts +1002 -0
- package/config.ts +476 -0
- package/context-engine.ts +1700 -0
- package/dist/auto-recall.js +167 -0
- package/dist/client.js +502 -0
- package/dist/commands/setup.js +815 -0
- package/dist/config.js +352 -0
- package/dist/context-engine.js +1324 -0
- package/dist/index.js +1194 -0
- package/dist/memory-ranking.js +221 -0
- package/dist/process-manager.js +127 -0
- package/dist/runtime-utils.js +7 -0
- package/dist/session-transcript-repair.js +427 -0
- package/dist/text-utils.js +453 -0
- package/dist/tool-call-id.js +254 -0
- package/index.ts +1597 -0
- package/install-manifest.json +47 -0
- package/memory-ranking.ts +267 -0
- package/openclaw.plugin.json +331 -0
- package/package.json +75 -0
- package/process-manager.ts +169 -0
- package/runtime-utils.ts +8 -0
- package/session-transcript-repair.ts +530 -0
- package/skills/install-openviking-memory/SKILL.md +665 -0
- package/text-utils.ts +524 -0
- package/tool-call-id.ts +331 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"manifestVersion": "1.0",
|
|
3
|
+
"pluginVersion": "2026.5.8",
|
|
4
|
+
"plugin": {
|
|
5
|
+
"id": "openviking",
|
|
6
|
+
"kind": "context-engine",
|
|
7
|
+
"slot": "contextEngine"
|
|
8
|
+
},
|
|
9
|
+
"files": {
|
|
10
|
+
"required": [
|
|
11
|
+
"index.ts",
|
|
12
|
+
"config.ts",
|
|
13
|
+
"context-engine.ts",
|
|
14
|
+
"auto-recall.ts",
|
|
15
|
+
"client.ts",
|
|
16
|
+
"process-manager.ts",
|
|
17
|
+
"memory-ranking.ts",
|
|
18
|
+
"text-utils.ts",
|
|
19
|
+
"tool-call-id.ts",
|
|
20
|
+
"session-transcript-repair.ts",
|
|
21
|
+
"runtime-utils.ts",
|
|
22
|
+
"commands/setup.ts",
|
|
23
|
+
"tsconfig.json",
|
|
24
|
+
"tsconfig.build.json",
|
|
25
|
+
"package.json",
|
|
26
|
+
"openclaw.plugin.json"
|
|
27
|
+
],
|
|
28
|
+
"optional": [
|
|
29
|
+
"package-lock.json",
|
|
30
|
+
".gitignore",
|
|
31
|
+
"skills/install-openviking-memory/SKILL.md",
|
|
32
|
+
"INSTALL-AGENT.md"
|
|
33
|
+
]
|
|
34
|
+
},
|
|
35
|
+
"npm": {
|
|
36
|
+
"install": true,
|
|
37
|
+
"omitDev": true,
|
|
38
|
+
"build": true,
|
|
39
|
+
"buildMinOpenclawVersion": "2026.5.3",
|
|
40
|
+
"buildScript": "build",
|
|
41
|
+
"pruneAfterBuild": true
|
|
42
|
+
},
|
|
43
|
+
"compatibility": {
|
|
44
|
+
"minOpenclawVersion": "2026.4.8",
|
|
45
|
+
"minOpenvikingVersion": "0.2.9"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import type { FindResultItem } from "./client.js";
|
|
2
|
+
|
|
3
|
+
export function clampScore(value: number | undefined): number {
|
|
4
|
+
if (typeof value !== "number" || Number.isNaN(value)) {
|
|
5
|
+
return 0;
|
|
6
|
+
}
|
|
7
|
+
return Math.max(0, Math.min(1, value));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function normalizeDedupeText(text: string): string {
|
|
11
|
+
return text.toLowerCase().replace(/\s+/g, " ").trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function isEventOrCaseMemory(item: FindResultItem): boolean {
|
|
15
|
+
const category = (item.category ?? "").toLowerCase();
|
|
16
|
+
const uri = item.uri.toLowerCase();
|
|
17
|
+
return (
|
|
18
|
+
category === "events" ||
|
|
19
|
+
category === "cases" ||
|
|
20
|
+
uri.includes("/events/") ||
|
|
21
|
+
uri.includes("/cases/")
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function getMemoryDedupeKey(item: FindResultItem): string {
|
|
26
|
+
const abstract = normalizeDedupeText(item.abstract ?? item.overview ?? "");
|
|
27
|
+
const category = (item.category ?? "").toLowerCase() || "unknown";
|
|
28
|
+
if (abstract && !isEventOrCaseMemory(item)) {
|
|
29
|
+
return `abstract:${category}:${abstract}`;
|
|
30
|
+
}
|
|
31
|
+
return `uri:${item.uri}`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function postProcessMemories(
|
|
35
|
+
items: FindResultItem[],
|
|
36
|
+
options: {
|
|
37
|
+
limit: number;
|
|
38
|
+
scoreThreshold: number;
|
|
39
|
+
leafOnly?: boolean;
|
|
40
|
+
},
|
|
41
|
+
): FindResultItem[] {
|
|
42
|
+
const deduped: FindResultItem[] = [];
|
|
43
|
+
const seen = new Set<string>();
|
|
44
|
+
const sorted = [...items].sort((a, b) => clampScore(b.score) - clampScore(a.score));
|
|
45
|
+
for (const item of sorted) {
|
|
46
|
+
if (options.leafOnly && item.level !== 2) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (clampScore(item.score) < options.scoreThreshold) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const key = getMemoryDedupeKey(item);
|
|
53
|
+
if (seen.has(key)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
seen.add(key);
|
|
57
|
+
deduped.push(item);
|
|
58
|
+
if (deduped.length >= options.limit) {
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return deduped;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function formatMemoryLines(items: FindResultItem[]): string {
|
|
66
|
+
return items
|
|
67
|
+
.map((item, index) => {
|
|
68
|
+
const score = clampScore(item.score);
|
|
69
|
+
const abstract = item.abstract?.trim() || item.overview?.trim() || item.uri;
|
|
70
|
+
const category = item.category ?? "memory";
|
|
71
|
+
return `${index + 1}. [${category}] ${abstract} (${(score * 100).toFixed(0)}%)`;
|
|
72
|
+
})
|
|
73
|
+
.join("\n");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function trimForLog(value: string, limit = 260): string {
|
|
77
|
+
const normalized = value.trim();
|
|
78
|
+
if (normalized.length <= limit) {
|
|
79
|
+
return normalized;
|
|
80
|
+
}
|
|
81
|
+
return `${normalized.slice(0, limit)}...`;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function toJsonLog(value: unknown, maxLen = 6000): string {
|
|
85
|
+
try {
|
|
86
|
+
const json = JSON.stringify(value);
|
|
87
|
+
if (json.length <= maxLen) {
|
|
88
|
+
return json;
|
|
89
|
+
}
|
|
90
|
+
return JSON.stringify({
|
|
91
|
+
truncated: true,
|
|
92
|
+
length: json.length,
|
|
93
|
+
preview: `${json.slice(0, maxLen)}...`,
|
|
94
|
+
});
|
|
95
|
+
} catch {
|
|
96
|
+
return JSON.stringify({ error: "stringify_failed" });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function summarizeInjectionMemories(items: FindResultItem[]): Array<Record<string, unknown>> {
|
|
101
|
+
return items.map((item) => ({
|
|
102
|
+
uri: item.uri,
|
|
103
|
+
category: item.category ?? null,
|
|
104
|
+
abstract: trimForLog(item.abstract?.trim() || item.overview?.trim() || item.uri, 180),
|
|
105
|
+
score: clampScore(item.score),
|
|
106
|
+
is_leaf: item.level === 2,
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function summarizeExtractedMemories(
|
|
111
|
+
items: Array<Record<string, unknown>>,
|
|
112
|
+
): Array<Record<string, unknown>> {
|
|
113
|
+
return items.slice(0, 10).map((item) => {
|
|
114
|
+
const abstractRaw =
|
|
115
|
+
typeof item.abstract === "string"
|
|
116
|
+
? item.abstract
|
|
117
|
+
: typeof item.overview === "string"
|
|
118
|
+
? item.overview
|
|
119
|
+
: typeof item.title === "string"
|
|
120
|
+
? item.title
|
|
121
|
+
: "";
|
|
122
|
+
return {
|
|
123
|
+
uri: typeof item.uri === "string" ? item.uri : null,
|
|
124
|
+
category: typeof item.category === "string" ? item.category : null,
|
|
125
|
+
abstract: trimForLog(abstractRaw, 180),
|
|
126
|
+
is_leaf: item.level === 2,
|
|
127
|
+
};
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function isPreferencesMemory(item: FindResultItem): boolean {
|
|
132
|
+
return (
|
|
133
|
+
item.category === "preferences" ||
|
|
134
|
+
item.uri.includes("/preferences/") ||
|
|
135
|
+
item.uri.endsWith("/preferences")
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function isEventMemory(item: FindResultItem): boolean {
|
|
140
|
+
const category = (item.category ?? "").toLowerCase();
|
|
141
|
+
return category === "events" || item.uri.includes("/events/");
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function isLeafLikeMemory(item: FindResultItem): boolean {
|
|
145
|
+
return item.level === 2;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const PREFERENCE_QUERY_RE = /prefer|preference|favorite|favourite|like|偏好|喜欢|爱好|更倾向/i;
|
|
149
|
+
const TEMPORAL_QUERY_RE =
|
|
150
|
+
/when|what time|date|day|month|year|yesterday|today|tomorrow|last|next|什么时候|何时|哪天|几月|几年|昨天|今天|明天|上周|下周|上个月|下个月|去年|明年/i;
|
|
151
|
+
const QUERY_TOKEN_RE = /[a-z0-9]{2,}/gi;
|
|
152
|
+
const QUERY_TOKEN_STOPWORDS = new Set([
|
|
153
|
+
"what",
|
|
154
|
+
"when",
|
|
155
|
+
"where",
|
|
156
|
+
"which",
|
|
157
|
+
"who",
|
|
158
|
+
"whom",
|
|
159
|
+
"whose",
|
|
160
|
+
"why",
|
|
161
|
+
"how",
|
|
162
|
+
"did",
|
|
163
|
+
"does",
|
|
164
|
+
"is",
|
|
165
|
+
"are",
|
|
166
|
+
"was",
|
|
167
|
+
"were",
|
|
168
|
+
"the",
|
|
169
|
+
"and",
|
|
170
|
+
"for",
|
|
171
|
+
"with",
|
|
172
|
+
"from",
|
|
173
|
+
"that",
|
|
174
|
+
"this",
|
|
175
|
+
"your",
|
|
176
|
+
"you",
|
|
177
|
+
]);
|
|
178
|
+
|
|
179
|
+
type RecallQueryProfile = {
|
|
180
|
+
tokens: string[];
|
|
181
|
+
wantsPreference: boolean;
|
|
182
|
+
wantsTemporal: boolean;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
function buildRecallQueryProfile(query: string): RecallQueryProfile {
|
|
186
|
+
const text = query.trim();
|
|
187
|
+
const allTokens = text.toLowerCase().match(QUERY_TOKEN_RE) ?? [];
|
|
188
|
+
const tokens = allTokens.filter((token) => !QUERY_TOKEN_STOPWORDS.has(token));
|
|
189
|
+
return {
|
|
190
|
+
tokens,
|
|
191
|
+
wantsPreference: PREFERENCE_QUERY_RE.test(text),
|
|
192
|
+
wantsTemporal: TEMPORAL_QUERY_RE.test(text),
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function lexicalOverlapBoost(tokens: string[], text: string): number {
|
|
197
|
+
if (tokens.length === 0 || !text) {
|
|
198
|
+
return 0;
|
|
199
|
+
}
|
|
200
|
+
const haystack = ` ${text.toLowerCase()} `;
|
|
201
|
+
let matched = 0;
|
|
202
|
+
for (const token of tokens.slice(0, 8)) {
|
|
203
|
+
if (haystack.includes(` ${token} `) || haystack.includes(token)) {
|
|
204
|
+
matched += 1;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return Math.min(0.2, (matched / Math.min(tokens.length, 4)) * 0.2);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function rankForInjection(item: FindResultItem, query: RecallQueryProfile): number {
|
|
211
|
+
// Keep ranking simple and stable: semantic score + light query-aware boosts.
|
|
212
|
+
const baseScore = clampScore(item.score);
|
|
213
|
+
const abstract = (item.abstract ?? item.overview ?? "").trim();
|
|
214
|
+
const leafBoost = isLeafLikeMemory(item) ? 0.12 : 0;
|
|
215
|
+
const eventBoost = query.wantsTemporal && isEventMemory(item) ? 0.1 : 0;
|
|
216
|
+
const preferenceBoost = query.wantsPreference && isPreferencesMemory(item) ? 0.08 : 0;
|
|
217
|
+
const overlapBoost = lexicalOverlapBoost(query.tokens, `${item.uri} ${abstract}`);
|
|
218
|
+
return baseScore + leafBoost + eventBoost + preferenceBoost + overlapBoost;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function pickMemoriesForInjection(
|
|
222
|
+
items: FindResultItem[],
|
|
223
|
+
limit: number,
|
|
224
|
+
queryText: string,
|
|
225
|
+
scoreThreshold: number = 0,
|
|
226
|
+
): FindResultItem[] {
|
|
227
|
+
if (items.length === 0 || limit <= 0) {
|
|
228
|
+
return [];
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const query = buildRecallQueryProfile(queryText);
|
|
232
|
+
const sorted = [...items].sort((a, b) => rankForInjection(b, query) - rankForInjection(a, query));
|
|
233
|
+
const deduped: FindResultItem[] = [];
|
|
234
|
+
const seen = new Set<string>();
|
|
235
|
+
for (const item of sorted) {
|
|
236
|
+
const abstractKey = (item.abstract ?? item.overview ?? "").trim().toLowerCase();
|
|
237
|
+
const key = abstractKey || item.uri;
|
|
238
|
+
if (seen.has(key)) {
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
seen.add(key);
|
|
242
|
+
deduped.push(item);
|
|
243
|
+
}
|
|
244
|
+
const leaves = deduped.filter((item) => isLeafLikeMemory(item));
|
|
245
|
+
if (leaves.length >= limit) {
|
|
246
|
+
return leaves.slice(0, limit);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const picked = [...leaves];
|
|
250
|
+
const used = new Set(leaves.map((item) => item.uri));
|
|
251
|
+
for (const item of deduped) {
|
|
252
|
+
if (picked.length >= limit) {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
if (used.has(item.uri)) {
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
// Respect score threshold when supplementing leaf memories with
|
|
259
|
+
// non-leaf items. Without this check, low-scoring memories bypass
|
|
260
|
+
// the threshold configured in recallScoreThreshold (see #1106).
|
|
261
|
+
if (clampScore(item.score) < scoreThreshold) {
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
picked.push(item);
|
|
265
|
+
}
|
|
266
|
+
return picked;
|
|
267
|
+
}
|
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openviking",
|
|
3
|
+
"name": "OpenViking",
|
|
4
|
+
"kind": "context-engine",
|
|
5
|
+
"description": "OpenClaw context-engine plugin for memory management — powered by OpenViking",
|
|
6
|
+
"activation": {
|
|
7
|
+
"onStartup": true,
|
|
8
|
+
"onCapabilities": [
|
|
9
|
+
"hook",
|
|
10
|
+
"tool"
|
|
11
|
+
]
|
|
12
|
+
},
|
|
13
|
+
"contracts": {
|
|
14
|
+
"tools": [
|
|
15
|
+
"ov_import",
|
|
16
|
+
"memory_search",
|
|
17
|
+
"memory_recall",
|
|
18
|
+
"memory_store",
|
|
19
|
+
"memory_forget",
|
|
20
|
+
"ov_archive_search",
|
|
21
|
+
"ov_archive_expand"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"commandAliases": [
|
|
25
|
+
{
|
|
26
|
+
"name": "setup",
|
|
27
|
+
"kind": "runtime-slash",
|
|
28
|
+
"cliCommand": "openviking"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"name": "status",
|
|
32
|
+
"kind": "runtime-slash",
|
|
33
|
+
"cliCommand": "openviking"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"providerAuthEnvVars": {
|
|
37
|
+
"openviking": [
|
|
38
|
+
"OPENVIKING_API_KEY",
|
|
39
|
+
"OPENVIKING_BASE_URL"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"skills": [
|
|
43
|
+
"./skills/install-openviking-memory"
|
|
44
|
+
],
|
|
45
|
+
"setup": {
|
|
46
|
+
"providers": [
|
|
47
|
+
{
|
|
48
|
+
"id": "openviking",
|
|
49
|
+
"authMethods": [
|
|
50
|
+
"api_key",
|
|
51
|
+
"trusted"
|
|
52
|
+
],
|
|
53
|
+
"envVars": [
|
|
54
|
+
"OPENVIKING_API_KEY",
|
|
55
|
+
"OPENVIKING_BASE_URL"
|
|
56
|
+
],
|
|
57
|
+
"cliFlags": {
|
|
58
|
+
"api_key": [
|
|
59
|
+
"--base-url",
|
|
60
|
+
"--api-key"
|
|
61
|
+
],
|
|
62
|
+
"trusted": [
|
|
63
|
+
"--base-url"
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"requiresRuntime": true,
|
|
69
|
+
"cliCommand": "openclaw openviking setup"
|
|
70
|
+
},
|
|
71
|
+
"uiHints": {
|
|
72
|
+
"baseUrl": {
|
|
73
|
+
"label": "OpenViking Base URL",
|
|
74
|
+
"placeholder": "http://127.0.0.1:1933",
|
|
75
|
+
"help": "HTTP URL when mode is remote (or ${OPENVIKING_BASE_URL})"
|
|
76
|
+
},
|
|
77
|
+
"agent_prefix": {
|
|
78
|
+
"label": "Agent Prefix",
|
|
79
|
+
"placeholder": "optional-prefix",
|
|
80
|
+
"help": "Optional OpenViking agent prefix. Empty: follow OpenClaw ctx.agentId directly. Non-empty: use `<prefix>_<OpenClaw ctx.agentId>` (sanitized to letters/digits/_/-). If OpenClaw ctx.agentId is unavailable, use OpenClaw default agent `main`."
|
|
81
|
+
},
|
|
82
|
+
"apiKey": {
|
|
83
|
+
"label": "OpenViking API Key",
|
|
84
|
+
"sensitive": true,
|
|
85
|
+
"placeholder": "${OPENVIKING_API_KEY}",
|
|
86
|
+
"help": "Optional API key for OpenViking server"
|
|
87
|
+
},
|
|
88
|
+
"accountId": {
|
|
89
|
+
"label": "Account ID",
|
|
90
|
+
"placeholder": "(derived from API key)",
|
|
91
|
+
"help": "Advanced option. Tenant account ID. Only needed when explicitly sending identity headers, such as root-key or trusted deployments. With a user key the server derives identity from the key.",
|
|
92
|
+
"advanced": true
|
|
93
|
+
},
|
|
94
|
+
"userId": {
|
|
95
|
+
"label": "User ID",
|
|
96
|
+
"placeholder": "(derived from API key)",
|
|
97
|
+
"help": "Advanced option. Tenant user ID. Only needed when explicitly sending identity headers.",
|
|
98
|
+
"advanced": true
|
|
99
|
+
},
|
|
100
|
+
"isolateUserScopeByAgent": {
|
|
101
|
+
"label": "Isolate User Scope By Agent",
|
|
102
|
+
"placeholder": "false",
|
|
103
|
+
"help": "Canonical namespace policy. false (default): user alias expands to viking://user/<user_id>/... . true: expands to viking://user/<user_id>/agent/<agent_id>/... . Must match the server-side account namespace policy.",
|
|
104
|
+
"advanced": true
|
|
105
|
+
},
|
|
106
|
+
"isolateAgentScopeByUser": {
|
|
107
|
+
"label": "Isolate Agent Scope By User",
|
|
108
|
+
"placeholder": "false",
|
|
109
|
+
"help": "Canonical namespace policy. false (default): agent alias expands to viking://agent/<agent_id>/... . true: expands to viking://agent/<agent_id>/user/<user_id>/... . Must match the server-side account namespace policy.",
|
|
110
|
+
"advanced": true
|
|
111
|
+
},
|
|
112
|
+
"agentScopeMode": {
|
|
113
|
+
"label": "Deprecated Agent Scope Mode",
|
|
114
|
+
"placeholder": "agent",
|
|
115
|
+
"help": "Deprecated compatibility alias for older routing. Prefer isolateUserScopeByAgent / isolateAgentScopeByUser. Explicit user_agent => false/true, explicit agent => false/false. When fully unset, the plugin defaults to false/false to match the current server-side policy.",
|
|
116
|
+
"advanced": true
|
|
117
|
+
},
|
|
118
|
+
"targetUri": {
|
|
119
|
+
"label": "Search Target URI",
|
|
120
|
+
"placeholder": "viking://user/memories",
|
|
121
|
+
"help": "Default OpenViking target URI for memory search"
|
|
122
|
+
},
|
|
123
|
+
"timeoutMs": {
|
|
124
|
+
"label": "Request Timeout (ms)",
|
|
125
|
+
"placeholder": "15000",
|
|
126
|
+
"advanced": true
|
|
127
|
+
},
|
|
128
|
+
"autoCapture": {
|
|
129
|
+
"label": "Auto-Capture",
|
|
130
|
+
"help": "Extract memories from recent conversation messages via OpenViking sessions"
|
|
131
|
+
},
|
|
132
|
+
"captureMode": {
|
|
133
|
+
"label": "Capture Mode",
|
|
134
|
+
"placeholder": "semantic",
|
|
135
|
+
"advanced": true,
|
|
136
|
+
"help": "semantic captures all eligible user text; keyword uses trigger regex first"
|
|
137
|
+
},
|
|
138
|
+
"captureMaxLength": {
|
|
139
|
+
"label": "Capture Max Length",
|
|
140
|
+
"placeholder": "24000",
|
|
141
|
+
"advanced": true,
|
|
142
|
+
"help": "Maximum sanitized user text length allowed for auto-capture"
|
|
143
|
+
},
|
|
144
|
+
"autoRecall": {
|
|
145
|
+
"label": "Auto-Recall",
|
|
146
|
+
"help": "Inject relevant OpenViking memories into agent context"
|
|
147
|
+
},
|
|
148
|
+
"recallResources": {
|
|
149
|
+
"label": "Recall Resources",
|
|
150
|
+
"help": "Include resources (viking://resources) in auto-recall and default memory_recall search. Enables account-level shared knowledge retrieval.",
|
|
151
|
+
"advanced": true
|
|
152
|
+
},
|
|
153
|
+
"recallLimit": {
|
|
154
|
+
"label": "Recall Limit",
|
|
155
|
+
"placeholder": "6",
|
|
156
|
+
"advanced": true
|
|
157
|
+
},
|
|
158
|
+
"recallScoreThreshold": {
|
|
159
|
+
"label": "Recall Score Threshold",
|
|
160
|
+
"placeholder": "0.15",
|
|
161
|
+
"advanced": true
|
|
162
|
+
},
|
|
163
|
+
"recallMaxInjectedChars": {
|
|
164
|
+
"label": "Recall Max Injected Chars",
|
|
165
|
+
"placeholder": "4000",
|
|
166
|
+
"advanced": true,
|
|
167
|
+
"help": "Maximum total characters for auto-recall memory injection. Complete memories that do not fit are skipped, not truncated."
|
|
168
|
+
},
|
|
169
|
+
"recallMaxContentChars": {
|
|
170
|
+
"label": "Deprecated Recall Max Content Chars",
|
|
171
|
+
"placeholder": "5000",
|
|
172
|
+
"advanced": true,
|
|
173
|
+
"help": "Deprecated compatibility option and will be removed in a future release. Auto-recall now keeps individual memories intact and uses recallMaxInjectedChars."
|
|
174
|
+
},
|
|
175
|
+
"recallPreferAbstract": {
|
|
176
|
+
"label": "Recall Prefer Abstract",
|
|
177
|
+
"advanced": true,
|
|
178
|
+
"help": "Use memory abstract instead of fetching full content when available"
|
|
179
|
+
},
|
|
180
|
+
"recallTokenBudget": {
|
|
181
|
+
"label": "Deprecated Recall Token Budget",
|
|
182
|
+
"placeholder": "4000",
|
|
183
|
+
"advanced": true,
|
|
184
|
+
"help": "Deprecated compatibility alias and will be removed in a future release. Use recallMaxInjectedChars."
|
|
185
|
+
},
|
|
186
|
+
"bypassSessionPatterns": {
|
|
187
|
+
"label": "Bypass Session Patterns",
|
|
188
|
+
"placeholder": "agent:*:cron:**",
|
|
189
|
+
"help": "Completely bypass OpenViking for matching session keys. Use * within one segment and ** across segments.",
|
|
190
|
+
"advanced": true
|
|
191
|
+
},
|
|
192
|
+
"commitTokenThreshold": {
|
|
193
|
+
"label": "Commit Token Threshold",
|
|
194
|
+
"placeholder": "20000",
|
|
195
|
+
"advanced": true,
|
|
196
|
+
"help": "Minimum estimated pending tokens before auto-commit triggers. Set to 0 to commit every turn."
|
|
197
|
+
},
|
|
198
|
+
"commitKeepRecentCount": {
|
|
199
|
+
"label": "Commit Keep Recent Count",
|
|
200
|
+
"placeholder": "10",
|
|
201
|
+
"advanced": true,
|
|
202
|
+
"help": "WM v2: number of most-recent messages kept live after an afterTurn commit. Compact path always uses 0."
|
|
203
|
+
},
|
|
204
|
+
"emitStandardDiagnostics": {
|
|
205
|
+
"label": "Standard diagnostics (diag JSON lines)",
|
|
206
|
+
"advanced": true,
|
|
207
|
+
"help": "Emit structured openviking: diag {...} for assemble/afterTurn. Set false to disable."
|
|
208
|
+
},
|
|
209
|
+
"logFindRequests": {
|
|
210
|
+
"label": "Log find requests",
|
|
211
|
+
"help": "Log tenant routing: /search/find + session messages/commit (X-OpenViking-*; not apiKey). Or set env OPENVIKING_LOG_ROUTING=1 or OPENVIKING_DEBUG=1.",
|
|
212
|
+
"advanced": true
|
|
213
|
+
}
|
|
214
|
+
},
|
|
215
|
+
"configSchema": {
|
|
216
|
+
"type": "object",
|
|
217
|
+
"additionalProperties": false,
|
|
218
|
+
"properties": {
|
|
219
|
+
"mode": {
|
|
220
|
+
"type": "string",
|
|
221
|
+
"description": "Legacy field kept for backward compatibility. Only 'remote' is supported."
|
|
222
|
+
},
|
|
223
|
+
"baseUrl": {
|
|
224
|
+
"type": "string"
|
|
225
|
+
},
|
|
226
|
+
"agent_prefix": {
|
|
227
|
+
"type": "string"
|
|
228
|
+
},
|
|
229
|
+
"agentId": {
|
|
230
|
+
"type": "string",
|
|
231
|
+
"description": "Deprecated: use agent_prefix instead"
|
|
232
|
+
},
|
|
233
|
+
"serverAuthMode": {
|
|
234
|
+
"type": "string",
|
|
235
|
+
"description": "Deprecated and ignored. Tenant identity headers are controlled by explicit accountId/userId."
|
|
236
|
+
},
|
|
237
|
+
"apiKey": {
|
|
238
|
+
"type": "string"
|
|
239
|
+
},
|
|
240
|
+
"accountId": {
|
|
241
|
+
"type": "string"
|
|
242
|
+
},
|
|
243
|
+
"userId": {
|
|
244
|
+
"type": "string"
|
|
245
|
+
},
|
|
246
|
+
"isolateUserScopeByAgent": {
|
|
247
|
+
"type": "boolean"
|
|
248
|
+
},
|
|
249
|
+
"isolateAgentScopeByUser": {
|
|
250
|
+
"type": "boolean"
|
|
251
|
+
},
|
|
252
|
+
"agentScopeMode": {
|
|
253
|
+
"type": "string"
|
|
254
|
+
},
|
|
255
|
+
"targetUri": {
|
|
256
|
+
"type": "string"
|
|
257
|
+
},
|
|
258
|
+
"timeoutMs": {
|
|
259
|
+
"type": "number"
|
|
260
|
+
},
|
|
261
|
+
"autoCapture": {
|
|
262
|
+
"type": "boolean"
|
|
263
|
+
},
|
|
264
|
+
"captureMode": {
|
|
265
|
+
"type": "string"
|
|
266
|
+
},
|
|
267
|
+
"captureMaxLength": {
|
|
268
|
+
"type": "number"
|
|
269
|
+
},
|
|
270
|
+
"autoRecall": {
|
|
271
|
+
"type": "boolean"
|
|
272
|
+
},
|
|
273
|
+
"recallResources": {
|
|
274
|
+
"type": "boolean"
|
|
275
|
+
},
|
|
276
|
+
"recallLimit": {
|
|
277
|
+
"type": "number"
|
|
278
|
+
},
|
|
279
|
+
"recallScoreThreshold": {
|
|
280
|
+
"type": "number"
|
|
281
|
+
},
|
|
282
|
+
"recallMaxInjectedChars": {
|
|
283
|
+
"type": "number"
|
|
284
|
+
},
|
|
285
|
+
"recallMaxContentChars": {
|
|
286
|
+
"type": "number"
|
|
287
|
+
},
|
|
288
|
+
"recallPreferAbstract": {
|
|
289
|
+
"type": "boolean"
|
|
290
|
+
},
|
|
291
|
+
"recallTokenBudget": {
|
|
292
|
+
"type": "number"
|
|
293
|
+
},
|
|
294
|
+
"commitTokenThreshold": {
|
|
295
|
+
"type": "number"
|
|
296
|
+
},
|
|
297
|
+
"commitKeepRecentCount": {
|
|
298
|
+
"type": "number",
|
|
299
|
+
"minimum": 0,
|
|
300
|
+
"maximum": 1000
|
|
301
|
+
},
|
|
302
|
+
"bypassSessionPatterns": {
|
|
303
|
+
"type": "array",
|
|
304
|
+
"items": {
|
|
305
|
+
"type": "string"
|
|
306
|
+
}
|
|
307
|
+
},
|
|
308
|
+
"ingestReplyAssist": {
|
|
309
|
+
"type": "boolean"
|
|
310
|
+
},
|
|
311
|
+
"ingestReplyAssistMinSpeakerTurns": {
|
|
312
|
+
"type": "number"
|
|
313
|
+
},
|
|
314
|
+
"ingestReplyAssistMinChars": {
|
|
315
|
+
"type": "number"
|
|
316
|
+
},
|
|
317
|
+
"ingestReplyAssistIgnoreSessionPatterns": {
|
|
318
|
+
"type": "array",
|
|
319
|
+
"items": {
|
|
320
|
+
"type": "string"
|
|
321
|
+
}
|
|
322
|
+
},
|
|
323
|
+
"emitStandardDiagnostics": {
|
|
324
|
+
"type": "boolean"
|
|
325
|
+
},
|
|
326
|
+
"logFindRequests": {
|
|
327
|
+
"type": "boolean"
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|