@openviking/openclaw-plugin 2026.6.18 → 2026.7.15
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 +2 -2
- package/INSTALL-ZH.md +2 -2
- package/INSTALL.md +2 -2
- package/README.md +1 -1
- package/auto-recall.ts +6 -6
- package/client.ts +14 -6
- package/commands/setup.ts +40 -10
- package/config.ts +44 -8
- package/context-engine.ts +2 -1
- package/dist/auto-recall.js +5 -6
- package/dist/client.js +11 -4
- package/dist/commands/setup.js +26 -10
- package/dist/config.js +31 -6
- package/dist/context-engine.js +2 -1
- package/dist/index.js +4 -4
- package/dist/plugin/openviking-archive-tools.js +1 -2
- package/dist/plugin/openviking-client-runtime.js +7 -1
- package/dist/plugin/openviking-command-definitions.js +3 -3
- package/dist/plugin/openviking-import-tools.js +2 -2
- package/dist/plugin/openviking-memory-recall-tools.js +4 -4
- package/dist/plugin/openviking-memory-tools.js +12 -7
- package/dist/plugin/openviking-query-runtime.js +1 -1
- package/dist/plugin/openviking-query-tools.js +4 -4
- package/dist/plugin/openviking-recall-trace-runtime.js +3 -3
- package/dist/plugin/openviking-session-routing-runtime.js +9 -2
- package/dist/plugin/openviking-tool-result-tools.js +3 -3
- package/dist/query-config.js +7 -1
- package/dist/request-headers.js +19 -0
- package/dist/routing/identity-routing.js +27 -0
- package/dist/routing/memory-uri.js +1 -0
- package/dist/services/context-lifecycle-service.js +56 -23
- package/dist/services/context-message-adapter.js +2 -9
- package/dist/text-utils.js +1 -6
- package/index.ts +3 -3
- package/install-manifest.json +2 -1
- package/openclaw.plugin.json +20 -4
- package/package.json +6 -6
- package/plugin/command-registration.ts +2 -0
- package/plugin/openviking-archive-tools.ts +1 -4
- package/plugin/openviking-client-runtime.ts +8 -1
- package/plugin/openviking-command-definitions.ts +4 -3
- package/plugin/openviking-import-tools.ts +4 -2
- package/plugin/openviking-memory-recall-tools.ts +6 -4
- package/plugin/openviking-memory-tools.ts +19 -11
- package/plugin/openviking-query-runtime.ts +1 -1
- package/plugin/openviking-query-tools.ts +6 -4
- package/plugin/openviking-recall-trace-runtime.ts +4 -3
- package/plugin/openviking-recall-trace-tools.ts +2 -0
- package/plugin/openviking-session-routing-runtime.ts +15 -1
- package/plugin/openviking-tool-result-tools.ts +0 -6
- package/query-config.ts +7 -1
- package/request-headers.ts +29 -0
- package/routing/identity-routing.ts +41 -0
- package/routing/memory-uri.ts +1 -0
- package/services/context-lifecycle-service.ts +69 -25
- package/services/context-message-adapter.ts +2 -9
- package/services/setup/probe-service.ts +35 -6
- package/services/setup/setup-flow.ts +61 -7
- package/skills/install-openviking-memory/SKILL.md +29 -15
- package/skills/openviking-context-database/SKILL.md +3 -3
- package/text-utils.ts +1 -6
package/dist/commands/setup.js
CHANGED
|
@@ -4,6 +4,7 @@ import * as path from "node:path";
|
|
|
4
4
|
import * as readline from "node:readline";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
6
|
import { getEnv } from "../runtime-utils.js";
|
|
7
|
+
import { cleanOpenVikingRequestHeaders, resolveOpenVikingRequestHeaders, } from "../request-headers.js";
|
|
7
8
|
const HOME = os.homedir();
|
|
8
9
|
const OPENCLAW_DIR = getEnv("OPENCLAW_STATE_DIR") || path.join(HOME, ".openclaw");
|
|
9
10
|
const DEFAULT_REMOTE_URL = "http://127.0.0.1:1933";
|
|
@@ -55,6 +56,7 @@ const PLUGIN_VERSION = readPluginVersion();
|
|
|
55
56
|
const { min: COMPATIBLE_SERVER_MIN, max: COMPATIBLE_SERVER_MAX } = readCompatRangeFromManifest();
|
|
56
57
|
const CONFIG_KEYS_TO_PRESERVE = [
|
|
57
58
|
"targetUri",
|
|
59
|
+
"headers",
|
|
58
60
|
"timeoutMs",
|
|
59
61
|
"autoCapture",
|
|
60
62
|
"captureMode",
|
|
@@ -68,7 +70,7 @@ const CONFIG_KEYS_TO_PRESERVE = [
|
|
|
68
70
|
"recallMaxContentChars",
|
|
69
71
|
"recallPreferAbstract",
|
|
70
72
|
"recallTokenBudget",
|
|
71
|
-
"
|
|
73
|
+
"commitTokenThresholdRatio",
|
|
72
74
|
"commitKeepRecentCount",
|
|
73
75
|
"bypassSessionPatterns",
|
|
74
76
|
"emitStandardDiagnostics",
|
|
@@ -84,6 +86,10 @@ function maskKey(key) {
|
|
|
84
86
|
return "****";
|
|
85
87
|
return `${key.slice(0, 4)}...${key.slice(-4)}`;
|
|
86
88
|
}
|
|
89
|
+
function nonEmptyOpenVikingRequestHeaders(value) {
|
|
90
|
+
const headers = cleanOpenVikingRequestHeaders(value);
|
|
91
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
92
|
+
}
|
|
87
93
|
function isValidPeerPrefixInput(value) {
|
|
88
94
|
const trimmed = value.trim();
|
|
89
95
|
return !trimmed || /^[a-zA-Z0-9_-]+$/.test(trimmed);
|
|
@@ -234,14 +240,17 @@ function formatCompatRange() {
|
|
|
234
240
|
return `<= ${COMPATIBLE_SERVER_MAX}`;
|
|
235
241
|
return "any";
|
|
236
242
|
}
|
|
237
|
-
async function probeApiKeyType(baseUrl, apiKey) {
|
|
243
|
+
async function probeApiKeyType(baseUrl, apiKey, configuredHeaders) {
|
|
238
244
|
if (!apiKey)
|
|
239
245
|
return { keyType: "no_key", needsAccountId: false, needsUserId: false, detail: "No API key configured" };
|
|
240
246
|
const controller = new AbortController();
|
|
241
247
|
const timeoutId = setTimeout(() => controller.abort(), 10_000);
|
|
242
248
|
const sessionsUrl = `${baseUrl.replace(/\/+$/, "")}/api/v1/sessions?limit=1`;
|
|
243
249
|
try {
|
|
244
|
-
const
|
|
250
|
+
const configuredRequestHeaders = resolveOpenVikingRequestHeaders({ headers: configuredHeaders });
|
|
251
|
+
const headers = {};
|
|
252
|
+
headers["X-API-Key"] = apiKey;
|
|
253
|
+
Object.assign(headers, configuredRequestHeaders);
|
|
245
254
|
const response = await fetch(sessionsUrl, {
|
|
246
255
|
headers,
|
|
247
256
|
signal: controller.signal,
|
|
@@ -278,6 +287,7 @@ async function probeApiKeyType(baseUrl, apiKey) {
|
|
|
278
287
|
"X-API-Key": apiKey,
|
|
279
288
|
"X-OpenViking-Account": "__probe__",
|
|
280
289
|
"X-OpenViking-User": "__probe__",
|
|
290
|
+
...configuredRequestHeaders,
|
|
281
291
|
};
|
|
282
292
|
const probe2 = await fetch(sessionsUrl, {
|
|
283
293
|
headers: probeHeaders,
|
|
@@ -307,13 +317,16 @@ async function probeApiKeyType(baseUrl, apiKey) {
|
|
|
307
317
|
clearTimeout(timeoutId);
|
|
308
318
|
}
|
|
309
319
|
}
|
|
310
|
-
async function checkServiceHealth(baseUrl, apiKey) {
|
|
320
|
+
async function checkServiceHealth(baseUrl, apiKey, configuredHeaders) {
|
|
311
321
|
const controller = new AbortController();
|
|
312
322
|
const timeoutId = setTimeout(() => controller.abort(), 10_000);
|
|
313
323
|
try {
|
|
324
|
+
const configuredRequestHeaders = resolveOpenVikingRequestHeaders({ headers: configuredHeaders });
|
|
314
325
|
const headers = {};
|
|
315
|
-
if (apiKey)
|
|
326
|
+
if (apiKey) {
|
|
316
327
|
headers["X-API-Key"] = apiKey;
|
|
328
|
+
}
|
|
329
|
+
Object.assign(headers, configuredRequestHeaders);
|
|
317
330
|
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/health`, {
|
|
318
331
|
headers,
|
|
319
332
|
signal: controller.signal,
|
|
@@ -602,8 +615,9 @@ function printCompatibilityWarning(zh, health) {
|
|
|
602
615
|
async function runRemoteCheck(zh, existing) {
|
|
603
616
|
const baseUrl = String(existing.baseUrl ?? DEFAULT_REMOTE_URL);
|
|
604
617
|
const apiKey = existing.apiKey ? String(existing.apiKey) : undefined;
|
|
618
|
+
const headers = nonEmptyOpenVikingRequestHeaders(existing.headers);
|
|
605
619
|
console.log(tr(zh, `Testing connectivity to ${baseUrl}...`, `正在测试连接 ${baseUrl}...`));
|
|
606
|
-
const health = await checkServiceHealth(baseUrl, apiKey);
|
|
620
|
+
const health = await checkServiceHealth(baseUrl, apiKey, headers);
|
|
607
621
|
if (health.ok) {
|
|
608
622
|
const ver = health.version ? ` (version: ${health.version})` : "";
|
|
609
623
|
console.log(` ✓ ${tr(zh, `Connected successfully${ver}`, `连接成功${ver}`)}`);
|
|
@@ -771,8 +785,9 @@ async function getStatus(configPath) {
|
|
|
771
785
|
}
|
|
772
786
|
const baseUrl = String(existing.baseUrl ?? DEFAULT_REMOTE_URL);
|
|
773
787
|
const apiKey = existing.apiKey ? String(existing.apiKey) : undefined;
|
|
774
|
-
const
|
|
775
|
-
const
|
|
788
|
+
const headers = nonEmptyOpenVikingRequestHeaders(existing.headers);
|
|
789
|
+
const health = await checkServiceHealth(baseUrl, apiKey, headers);
|
|
790
|
+
const keyProbe = health.ok ? await probeApiKeyType(baseUrl, apiKey, headers) : undefined;
|
|
776
791
|
const peerPrefix = resolveExistingPeerPrefix(existing);
|
|
777
792
|
return {
|
|
778
793
|
configured: true,
|
|
@@ -858,13 +873,14 @@ async function setupRemote(zh, configPath, existing, q) {
|
|
|
858
873
|
const defaultApiKey = existing?.apiKey ? String(existing.apiKey) : "";
|
|
859
874
|
const defaultPeerRole = resolveExistingPeerRole(existing);
|
|
860
875
|
const defaultPeerPrefix = resolveExistingPeerPrefix(existing);
|
|
876
|
+
const headers = nonEmptyOpenVikingRequestHeaders(existing?.headers);
|
|
861
877
|
const baseUrl = await q(tr(zh, "OpenViking server URL", "OpenViking 服务器地址"), defaultUrl);
|
|
862
878
|
const apiKey = await q(tr(zh, "API Key (optional)", "API Key(可选)"), defaultApiKey);
|
|
863
879
|
let accountId = existing?.accountId ? String(existing.accountId) : "";
|
|
864
880
|
let userId = existing?.userId ? String(existing.userId) : "";
|
|
865
881
|
if (apiKey) {
|
|
866
882
|
console.log(tr(zh, " Detecting API key type...", " 正在检测 API Key 类型..."));
|
|
867
|
-
const probe = await probeApiKeyType(baseUrl, apiKey);
|
|
883
|
+
const probe = await probeApiKeyType(baseUrl, apiKey, headers);
|
|
868
884
|
if (probe.keyType === "root_key") {
|
|
869
885
|
console.log(tr(zh, " ⚠ Root API key detected. accountId and userId are required.", " ⚠ 检测到 Root API Key,需要提供 accountId 和 userId。"));
|
|
870
886
|
accountId = await q(tr(zh, "Account ID (required for root key)", "Account ID(root key 必填)"), accountId);
|
|
@@ -880,7 +896,7 @@ async function setupRemote(zh, configPath, existing, q) {
|
|
|
880
896
|
: "";
|
|
881
897
|
console.log("");
|
|
882
898
|
console.log(tr(zh, `Testing connectivity to ${baseUrl}...`, `正在测试连接 ${baseUrl}...`));
|
|
883
|
-
const health = await checkServiceHealth(baseUrl, apiKey || undefined);
|
|
899
|
+
const health = await checkServiceHealth(baseUrl, apiKey || undefined, headers);
|
|
884
900
|
if (health.ok) {
|
|
885
901
|
const ver = health.version ? ` (version: ${health.version})` : "";
|
|
886
902
|
console.log(` ✓ ${tr(zh, `Connected successfully${ver}`, `连接成功${ver}`)}`);
|
package/dist/config.js
CHANGED
|
@@ -11,7 +11,7 @@ const DEFAULT_RECALL_SCORE_THRESHOLD = 0.15;
|
|
|
11
11
|
const DEFAULT_RECALL_MAX_CONTENT_CHARS = 5000;
|
|
12
12
|
const DEFAULT_RECALL_PREFER_ABSTRACT = false;
|
|
13
13
|
const DEFAULT_RECALL_MAX_INJECTED_CHARS = 4000;
|
|
14
|
-
const
|
|
14
|
+
const DEFAULT_COMMIT_TOKEN_THRESHOLD_RATIO = 0.5;
|
|
15
15
|
const DEFAULT_COMMIT_KEEP_RECENT_COUNT = 10;
|
|
16
16
|
const DEFAULT_BYPASS_SESSION_PATTERNS = [];
|
|
17
17
|
const DEFAULT_EMIT_STANDARD_DIAGNOSTICS = false;
|
|
@@ -168,6 +168,23 @@ function toRecord(value) {
|
|
|
168
168
|
? value
|
|
169
169
|
: {};
|
|
170
170
|
}
|
|
171
|
+
function toStringRecord(value, label) {
|
|
172
|
+
if (value === undefined || value === null) {
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
if (typeof value !== "object" || Array.isArray(value)) {
|
|
176
|
+
throw new Error(`${label} must be an object`);
|
|
177
|
+
}
|
|
178
|
+
const record = value;
|
|
179
|
+
const out = {};
|
|
180
|
+
for (const [key, val] of Object.entries(record)) {
|
|
181
|
+
if (typeof val !== "string") {
|
|
182
|
+
throw new Error(`${label}.${key} must be a string`);
|
|
183
|
+
}
|
|
184
|
+
out[key] = val;
|
|
185
|
+
}
|
|
186
|
+
return out;
|
|
187
|
+
}
|
|
171
188
|
function expandToolSelectors(value, fallback, label) {
|
|
172
189
|
const entries = toStringArray(value, fallback);
|
|
173
190
|
const seen = new Set();
|
|
@@ -250,6 +267,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
250
267
|
"peer_prefix",
|
|
251
268
|
"serverAuthMode",
|
|
252
269
|
"apiKey",
|
|
270
|
+
"headers",
|
|
253
271
|
"accountId",
|
|
254
272
|
"userId",
|
|
255
273
|
"targetUri",
|
|
@@ -267,6 +285,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
267
285
|
"recallPreferAbstract",
|
|
268
286
|
"recallTokenBudget",
|
|
269
287
|
"commitTokenThreshold",
|
|
288
|
+
"commitTokenThresholdRatio",
|
|
270
289
|
"commitKeepRecentCount",
|
|
271
290
|
"bypassSessionPatterns",
|
|
272
291
|
"ingestReplyAssist",
|
|
@@ -324,6 +343,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
324
343
|
peer_role: peerRole,
|
|
325
344
|
peer_prefix: peerPrefix,
|
|
326
345
|
apiKey: rawApiKey ? resolveEnvVars(rawApiKey) : "",
|
|
346
|
+
headers: toStringRecord(cfg.headers, "openviking config headers"),
|
|
327
347
|
accountId,
|
|
328
348
|
userId,
|
|
329
349
|
targetUri: typeof cfg.targetUri === "string" ? cfg.targetUri : DEFAULT_TARGET_URI,
|
|
@@ -342,7 +362,7 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
342
362
|
: DEFAULT_RECALL_PREFER_ABSTRACT,
|
|
343
363
|
recallMaxInjectedChars,
|
|
344
364
|
recallTokenBudget: recallMaxInjectedChars,
|
|
345
|
-
|
|
365
|
+
commitTokenThresholdRatio: Math.max(0, Math.min(1, toNumber(cfg.commitTokenThresholdRatio, DEFAULT_COMMIT_TOKEN_THRESHOLD_RATIO))),
|
|
346
366
|
commitKeepRecentCount: Math.max(0, Math.min(1_000, Math.floor(toNumber(cfg.commitKeepRecentCount, DEFAULT_COMMIT_KEEP_RECENT_COUNT)))),
|
|
347
367
|
bypassSessionPatterns: toStringArray(cfg.bypassSessionPatterns, toStringArray(cfg.ingestReplyAssistIgnoreSessionPatterns, DEFAULT_BYPASS_SESSION_PATTERNS)),
|
|
348
368
|
emitStandardDiagnostics: typeof cfg.emitStandardDiagnostics === "boolean"
|
|
@@ -405,6 +425,11 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
405
425
|
placeholder: "${OPENVIKING_API_KEY}",
|
|
406
426
|
help: "Optional API key for OpenViking server",
|
|
407
427
|
},
|
|
428
|
+
headers: {
|
|
429
|
+
label: "Headers",
|
|
430
|
+
advanced: true,
|
|
431
|
+
help: "Optional HTTP headers merged into every OpenViking request.",
|
|
432
|
+
},
|
|
408
433
|
accountId: {
|
|
409
434
|
label: "Account ID",
|
|
410
435
|
placeholder: "(derived from API key)",
|
|
@@ -503,11 +528,11 @@ export const memoryOpenVikingConfigSchema = {
|
|
|
503
528
|
help: "Completely bypass OpenViking for matching session keys. Use * within one segment and ** across segments.",
|
|
504
529
|
advanced: true,
|
|
505
530
|
},
|
|
506
|
-
|
|
507
|
-
label: "Commit Token Threshold",
|
|
508
|
-
placeholder: String(
|
|
531
|
+
commitTokenThresholdRatio: {
|
|
532
|
+
label: "Commit Token Threshold Ratio",
|
|
533
|
+
placeholder: String(DEFAULT_COMMIT_TOKEN_THRESHOLD_RATIO),
|
|
509
534
|
advanced: true,
|
|
510
|
-
help: "
|
|
535
|
+
help: "Auto-commit triggers once estimated pending tokens reach this fraction (0-1) of the model context window (e.g. 0.5 = 50%). Set to 0 to commit every turn.",
|
|
511
536
|
},
|
|
512
537
|
commitKeepRecentCount: {
|
|
513
538
|
label: "Commit Keep Recent Count",
|
package/dist/context-engine.js
CHANGED
|
@@ -135,7 +135,6 @@ export function createMemoryOpenVikingContextEngine(params) {
|
|
|
135
135
|
getClient,
|
|
136
136
|
logger,
|
|
137
137
|
rememberSessionAgentId,
|
|
138
|
-
resolveAgentId,
|
|
139
138
|
isBypassedSession,
|
|
140
139
|
});
|
|
141
140
|
}
|
|
@@ -204,12 +203,14 @@ export function createMemoryOpenVikingContextEngine(params) {
|
|
|
204
203
|
});
|
|
205
204
|
},
|
|
206
205
|
async afterTurn(afterTurnParams) {
|
|
206
|
+
const tokenBudget = validTokenBudget(afterTurnParams.tokenBudget) ?? 128_000;
|
|
207
207
|
await afterTurnOpenVikingSession({
|
|
208
208
|
sessionId: afterTurnParams.sessionId,
|
|
209
209
|
sessionKey: resolveSessionKey(afterTurnParams),
|
|
210
210
|
messages: afterTurnParams.messages,
|
|
211
211
|
prePromptMessageCount: afterTurnParams.prePromptMessageCount,
|
|
212
212
|
isHeartbeat: afterTurnParams.isHeartbeat,
|
|
213
|
+
tokenBudget,
|
|
213
214
|
runtimeContext: afterTurnParams.runtimeContext,
|
|
214
215
|
cfg,
|
|
215
216
|
getClient,
|
package/dist/index.js
CHANGED
|
@@ -25,8 +25,8 @@ import { registerOpenVikingRecallTraceTools } from "./plugin/openviking-recall-t
|
|
|
25
25
|
import { createOpenVikingRuntimeState } from "./plugin/openviking-runtime-state.js";
|
|
26
26
|
import { createOpenVikingSessionRoutingRuntime } from "./plugin/openviking-session-routing-runtime.js";
|
|
27
27
|
import { registerOpenVikingToolResultTools } from "./plugin/openviking-tool-result-tools.js";
|
|
28
|
-
import { boundTraceQuery, createMemoryStoreTempSessionId, createTraceId,
|
|
29
|
-
import { formatMessageFaithful
|
|
28
|
+
import { boundTraceQuery, createMemoryStoreTempSessionId, createTraceId, inferRecallResourceType, makeBypassedToolResult, previewText, } from "./plugin/openviking-runtime-utils.js";
|
|
29
|
+
import { formatMessageFaithful } from "./services/context-message-adapter.js";
|
|
30
30
|
import { clampScore, postProcessMemories, pickMemoriesForInjection, } from "./memory-ranking.js";
|
|
31
31
|
import { createMemoryOpenVikingContextEngine, } from "./context-engine.js";
|
|
32
32
|
import { openClawSessionRefToOvStorageId, openClawSessionToOvStorageId, } from "./routing/identity-routing.js";
|
|
@@ -80,6 +80,7 @@ const contextEnginePlugin = {
|
|
|
80
80
|
logger: api.logger,
|
|
81
81
|
});
|
|
82
82
|
const { rememberSessionAgentId, resolveAgentId, resolvePluginSessionRouting, toQueryConfigContext, } = createOpenVikingSessionRoutingRuntime({
|
|
83
|
+
peerRole: cfg.peer_role,
|
|
83
84
|
peerPrefix: cfg.peer_prefix,
|
|
84
85
|
logFindRequests: cfg.logFindRequests,
|
|
85
86
|
logger: api.logger,
|
|
@@ -182,8 +183,7 @@ const contextEnginePlugin = {
|
|
|
182
183
|
getClient,
|
|
183
184
|
normalizeSessionId: openClawSessionRefToOvStorageId,
|
|
184
185
|
createTempSessionId: createMemoryStoreTempSessionId,
|
|
185
|
-
|
|
186
|
-
toRoleId,
|
|
186
|
+
peerRole: cfg.peer_role,
|
|
187
187
|
resolvePluginSessionRouting,
|
|
188
188
|
isBypassedSession,
|
|
189
189
|
makeBypassedToolResult,
|
|
@@ -55,7 +55,6 @@ export function registerOpenVikingArchiveTools(deps) {
|
|
|
55
55
|
const result = await client.grepSessionArchives(ovSessionId, escapedQuery, {
|
|
56
56
|
archiveId,
|
|
57
57
|
caseInsensitive: true,
|
|
58
|
-
agentId,
|
|
59
58
|
});
|
|
60
59
|
const traceResults = (result.matches ?? []).slice(0, deps.traceRecallMaxResultsPerSearch).map((match) => ({
|
|
61
60
|
uri: match.uri,
|
|
@@ -175,7 +174,7 @@ export function registerOpenVikingArchiveTools(deps) {
|
|
|
175
174
|
}
|
|
176
175
|
try {
|
|
177
176
|
const client = await deps.getClient();
|
|
178
|
-
const detail = await client.getSessionArchive(session.ovSessionId, archiveId
|
|
177
|
+
const detail = await client.getSessionArchive(session.ovSessionId, archiveId);
|
|
179
178
|
const header = [
|
|
180
179
|
`## ${detail.archive_id}`,
|
|
181
180
|
detail.abstract ? `**Summary**: ${detail.abstract}` : "",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { OpenVikingClient } from "../client.js";
|
|
2
|
+
import { resolveOpenVikingRequestHeaders } from "../request-headers.js";
|
|
2
3
|
export function createOpenVikingClientRuntime(options) {
|
|
3
4
|
const { cfg, logger } = options;
|
|
4
5
|
if (cfg.logFindRequests) {
|
|
@@ -19,7 +20,12 @@ export function createOpenVikingClientRuntime(options) {
|
|
|
19
20
|
logger.info(msg);
|
|
20
21
|
}
|
|
21
22
|
: undefined;
|
|
22
|
-
const clientPromise = Promise.resolve(new OpenVikingClient(cfg.baseUrl, cfg.apiKey, cfg.peer_prefix, cfg.timeoutMs, cfg.accountId, cfg.userId, routingDebugLog, {
|
|
23
|
+
const clientPromise = Promise.resolve(new OpenVikingClient(cfg.baseUrl, cfg.apiKey, cfg.peer_prefix, cfg.timeoutMs, cfg.accountId, cfg.userId, routingDebugLog, {
|
|
24
|
+
transport: options.transport,
|
|
25
|
+
headers: resolveOpenVikingRequestHeaders({
|
|
26
|
+
headers: cfg.headers,
|
|
27
|
+
}),
|
|
28
|
+
}));
|
|
23
29
|
const getClient = () => clientPromise;
|
|
24
30
|
return {
|
|
25
31
|
getClient,
|
|
@@ -124,7 +124,7 @@ export function createOpenVikingCommandDefinitions(deps) {
|
|
|
124
124
|
}
|
|
125
125
|
const session = deps.resolvePluginSessionRouting(ctx);
|
|
126
126
|
const input = deps.parseAddResourceCommandArgs(ctx.args ?? "");
|
|
127
|
-
return toCommandResult(await deps.addResourceOpenViking(input, session.
|
|
127
|
+
return toCommandResult(await deps.addResourceOpenViking(input, session.actorPeerId));
|
|
128
128
|
}
|
|
129
129
|
catch (err) {
|
|
130
130
|
return { text: `OpenViking add resource failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -142,7 +142,7 @@ export function createOpenVikingCommandDefinitions(deps) {
|
|
|
142
142
|
}
|
|
143
143
|
const session = deps.resolvePluginSessionRouting(ctx);
|
|
144
144
|
const input = deps.parseAddSkillCommandArgs(ctx.args ?? "");
|
|
145
|
-
return toCommandResult(await deps.addSkillOpenViking(input, session.
|
|
145
|
+
return toCommandResult(await deps.addSkillOpenViking(input, session.actorPeerId));
|
|
146
146
|
}
|
|
147
147
|
catch (err) {
|
|
148
148
|
return { text: `OpenViking add skill failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -160,7 +160,7 @@ export function createOpenVikingCommandDefinitions(deps) {
|
|
|
160
160
|
}
|
|
161
161
|
const session = deps.resolvePluginSessionRouting(ctx);
|
|
162
162
|
const input = deps.parseOVSearchCommandArgs(ctx.args ?? "");
|
|
163
|
-
return toCommandResult(await deps.searchOpenViking(input, session.
|
|
163
|
+
return toCommandResult(await deps.searchOpenViking(input, session.actorPeerId, session));
|
|
164
164
|
}
|
|
165
165
|
catch (err) {
|
|
166
166
|
return { text: `OpenViking search failed: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -40,7 +40,7 @@ export function registerOpenVikingImportTools(deps) {
|
|
|
40
40
|
instruction: typeof params.instruction === "string" ? params.instruction : undefined,
|
|
41
41
|
wait: typeof params.wait === "boolean" ? params.wait : undefined,
|
|
42
42
|
timeout: typeof params.timeout === "number" ? params.timeout : undefined,
|
|
43
|
-
}, session.
|
|
43
|
+
}, session.actorPeerId);
|
|
44
44
|
return {
|
|
45
45
|
content: [{ type: "text", text: formatResourceImportText(result) }],
|
|
46
46
|
details: {
|
|
@@ -73,7 +73,7 @@ export function registerOpenVikingImportTools(deps) {
|
|
|
73
73
|
data: params.data,
|
|
74
74
|
wait: typeof params.wait === "boolean" ? params.wait : undefined,
|
|
75
75
|
timeout: typeof params.timeout === "number" ? params.timeout : undefined,
|
|
76
|
-
}, session.
|
|
76
|
+
}, session.actorPeerId);
|
|
77
77
|
return {
|
|
78
78
|
content: [{ type: "text", text: formatSkillImportText(result) }],
|
|
79
79
|
details: {
|
|
@@ -47,7 +47,7 @@ export function registerOpenVikingMemoryRecallTools(deps) {
|
|
|
47
47
|
const requestLimit = queryConfig.candidateLimit;
|
|
48
48
|
const recallClient = await deps.getClient();
|
|
49
49
|
if (deps.cfg.logFindRequests) {
|
|
50
|
-
deps.logger.info?.(`openviking: memory_recall X-OpenViking-Actor-Peer="${session.
|
|
50
|
+
deps.logger.info?.(`openviking: memory_recall X-OpenViking-Actor-Peer="${session.actorPeerId ?? "none"}" ` +
|
|
51
51
|
`(plugin defaultAgentId="${recallClient.getDefaultAgentId()}" is unused when session context is present)`);
|
|
52
52
|
}
|
|
53
53
|
let result;
|
|
@@ -57,7 +57,7 @@ export function registerOpenVikingMemoryRecallTools(deps) {
|
|
|
57
57
|
targetUri,
|
|
58
58
|
limit: requestLimit,
|
|
59
59
|
scoreThreshold: 0,
|
|
60
|
-
actorPeerId: session.
|
|
60
|
+
actorPeerId: session.actorPeerId,
|
|
61
61
|
});
|
|
62
62
|
const traceResults = [
|
|
63
63
|
...(result.memories ?? []).map((item) => toTraceResult(item, "memory", deps)),
|
|
@@ -84,7 +84,7 @@ export function registerOpenVikingMemoryRecallTools(deps) {
|
|
|
84
84
|
limit: requestLimit,
|
|
85
85
|
scoreThreshold: 0,
|
|
86
86
|
contextType: search.contextType,
|
|
87
|
-
actorPeerId: session.
|
|
87
|
+
actorPeerId: session.actorPeerId,
|
|
88
88
|
})));
|
|
89
89
|
const allMemories = [];
|
|
90
90
|
for (let index = 0; index < settled.length; index += 1) {
|
|
@@ -188,7 +188,7 @@ export function registerOpenVikingMemoryRecallTools(deps) {
|
|
|
188
188
|
details: { count: 0, total: result.total ?? 0, scoreThreshold },
|
|
189
189
|
};
|
|
190
190
|
}
|
|
191
|
-
const { lines: memoryLines } = await deps.buildMemoryLinesWithBudget(memories, (uri) => recallClient.read(uri, session.
|
|
191
|
+
const { lines: memoryLines } = await deps.buildMemoryLinesWithBudget(memories, (uri) => recallClient.read(uri, session.actorPeerId), {
|
|
192
192
|
recallPreferAbstract: false,
|
|
193
193
|
recallMaxInjectedChars: queryConfig.maxInjectedChars,
|
|
194
194
|
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from "@sinclair/typebox";
|
|
2
2
|
import { clampScore, postProcessMemories } from "../memory-ranking.js";
|
|
3
|
+
import { resolveOpenVikingMessagePeerId, } from "../routing/identity-routing.js";
|
|
3
4
|
import { isMemoryUri } from "../routing/memory-uri.js";
|
|
4
5
|
function totalCommitMemories(r) {
|
|
5
6
|
const m = r.memories_extracted;
|
|
@@ -11,7 +12,7 @@ export function registerOpenVikingMemoryTools(deps) {
|
|
|
11
12
|
deps.registerTool((ctx) => ({
|
|
12
13
|
name: "memory_store",
|
|
13
14
|
label: "Memory Store (OpenViking)",
|
|
14
|
-
description: "Store text in OpenViking memory pipeline by writing to a session and running memory extraction.",
|
|
15
|
+
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.",
|
|
15
16
|
parameters: Type.Object({
|
|
16
17
|
text: Type.String({ description: "Information to store as memory source text" }),
|
|
17
18
|
role: Type.Optional(Type.String({ description: "Session role, default user" })),
|
|
@@ -41,11 +42,15 @@ export function registerOpenVikingMemoryTools(deps) {
|
|
|
41
42
|
sessionId = deps.createTempSessionId();
|
|
42
43
|
usedTempSession = true;
|
|
43
44
|
}
|
|
44
|
-
const
|
|
45
|
-
|
|
45
|
+
const peerId = resolveOpenVikingMessagePeerId({
|
|
46
|
+
peerRole: deps.peerRole,
|
|
47
|
+
role,
|
|
48
|
+
personPeerId: session.actorPeerId,
|
|
49
|
+
assistantPeerId: session.actorPeerId,
|
|
50
|
+
});
|
|
51
|
+
await client.addSessionMessage(sessionId, role, [{ type: "text", text }], undefined, undefined, peerId);
|
|
46
52
|
const commitResult = await client.commitSession(sessionId, {
|
|
47
53
|
wait: true,
|
|
48
|
-
agentId: session.agentId,
|
|
49
54
|
keepRecentCount: 0,
|
|
50
55
|
});
|
|
51
56
|
const memoriesCount = totalCommitMemories(commitResult);
|
|
@@ -130,7 +135,7 @@ export function registerOpenVikingMemoryTools(deps) {
|
|
|
130
135
|
details: { action: "rejected", uri },
|
|
131
136
|
};
|
|
132
137
|
}
|
|
133
|
-
await client.deleteUri(uri, session.
|
|
138
|
+
await client.deleteUri(uri, session.actorPeerId);
|
|
134
139
|
return {
|
|
135
140
|
content: [{ type: "text", text: `Forgotten: ${uri}` }],
|
|
136
141
|
details: { action: "deleted", uri },
|
|
@@ -157,7 +162,7 @@ export function registerOpenVikingMemoryTools(deps) {
|
|
|
157
162
|
targetUri,
|
|
158
163
|
limit: requestLimit,
|
|
159
164
|
scoreThreshold: 0,
|
|
160
|
-
}, session.
|
|
165
|
+
}, session.actorPeerId);
|
|
161
166
|
const candidates = postProcessMemories(result.memories ?? [], {
|
|
162
167
|
limit: requestLimit,
|
|
163
168
|
scoreThreshold,
|
|
@@ -176,7 +181,7 @@ export function registerOpenVikingMemoryTools(deps) {
|
|
|
176
181
|
}
|
|
177
182
|
const top = candidates[0];
|
|
178
183
|
if (candidates.length === 1 && clampScore(top.score) >= 0.85) {
|
|
179
|
-
await client.deleteUri(top.uri, session.
|
|
184
|
+
await client.deleteUri(top.uri, session.actorPeerId);
|
|
180
185
|
return {
|
|
181
186
|
content: [{ type: "text", text: `Forgotten: ${top.uri}` }],
|
|
182
187
|
details: { action: "deleted", uri: top.uri, score: top.score ?? 0 },
|
|
@@ -337,7 +337,7 @@ export function createOpenVikingQueryRuntime(deps) {
|
|
|
337
337
|
sessionId: traceCtx?.sessionId,
|
|
338
338
|
sessionKey: traceCtx?.sessionKey,
|
|
339
339
|
ovSessionId: traceCtx?.ovSessionId,
|
|
340
|
-
agentId,
|
|
340
|
+
agentId: traceCtx?.agentId,
|
|
341
341
|
source: "ov_search",
|
|
342
342
|
operationType: "semantic_find",
|
|
343
343
|
resourceTypes: [...new Set(searches.map((search) => search.resourceType).filter((resourceType) => resourceType !== "archive"))],
|
|
@@ -21,7 +21,7 @@ export function registerOpenVikingQueryTools(deps) {
|
|
|
21
21
|
query: String(params.query ?? ""),
|
|
22
22
|
uri: typeof params.uri === "string" ? params.uri : undefined,
|
|
23
23
|
limit: typeof params.limit === "number" ? params.limit : undefined,
|
|
24
|
-
}, session.
|
|
24
|
+
}, session.actorPeerId, session);
|
|
25
25
|
},
|
|
26
26
|
}), { name: "ov_search" });
|
|
27
27
|
deps.registerTool((ctx) => ({
|
|
@@ -41,7 +41,7 @@ export function registerOpenVikingQueryTools(deps) {
|
|
|
41
41
|
const session = deps.resolvePluginSessionRouting(ctx);
|
|
42
42
|
return deps.readOpenVikingContent({
|
|
43
43
|
uri: String(params.uri ?? ""),
|
|
44
|
-
}, session.
|
|
44
|
+
}, session.actorPeerId);
|
|
45
45
|
},
|
|
46
46
|
}), { name: "ov_read" });
|
|
47
47
|
deps.registerTool((ctx) => ({
|
|
@@ -62,7 +62,7 @@ export function registerOpenVikingQueryTools(deps) {
|
|
|
62
62
|
const uris = Array.isArray(params.uris)
|
|
63
63
|
? params.uris.map((uri) => String(uri))
|
|
64
64
|
: [];
|
|
65
|
-
return deps.multiReadOpenVikingContent({ uris }, session.
|
|
65
|
+
return deps.multiReadOpenVikingContent({ uris }, session.actorPeerId);
|
|
66
66
|
},
|
|
67
67
|
}), { name: "ov_multi_read" });
|
|
68
68
|
deps.registerTool((ctx) => ({
|
|
@@ -85,7 +85,7 @@ export function registerOpenVikingQueryTools(deps) {
|
|
|
85
85
|
recursive: typeof params.recursive === "boolean" ? params.recursive : undefined,
|
|
86
86
|
simple: typeof params.simple === "boolean" ? params.simple : undefined,
|
|
87
87
|
limit: typeof params.limit === "number" ? params.limit : undefined,
|
|
88
|
-
}, session.
|
|
88
|
+
}, session.actorPeerId);
|
|
89
89
|
},
|
|
90
90
|
}), { name: "ov_list" });
|
|
91
91
|
}
|
|
@@ -157,11 +157,11 @@ export function createOpenVikingRecallTraceRuntime(deps) {
|
|
|
157
157
|
for (const fallbackQuery of fallbackIdentities) {
|
|
158
158
|
const fallback = await deps.traceRecorder.queryWithFallback(fallbackQuery);
|
|
159
159
|
if (fallback.entries.length > 0) {
|
|
160
|
-
return enrichTraceEntriesWithContent(fallback, shouldIncludeTraceContent(input), session.
|
|
160
|
+
return enrichTraceEntriesWithContent(fallback, shouldIncludeTraceContent(input), session.actorPeerId);
|
|
161
161
|
}
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
-
return enrichTraceEntriesWithContent(base, shouldIncludeTraceContent(input), session.
|
|
164
|
+
return enrichTraceEntriesWithContent(base, shouldIncludeTraceContent(input), session.actorPeerId);
|
|
165
165
|
};
|
|
166
166
|
const handleUriDetail = async (request) => {
|
|
167
167
|
const query = toQueryObject(request);
|
|
@@ -206,7 +206,7 @@ export function createOpenVikingRecallTraceRuntime(deps) {
|
|
|
206
206
|
}
|
|
207
207
|
try {
|
|
208
208
|
const client = await deps.getClient();
|
|
209
|
-
const content = await client.read(uri,
|
|
209
|
+
const content = await client.read(uri, session.actorPeerId);
|
|
210
210
|
const text = typeof content === "string" ? content : JSON.stringify(content, null, 2);
|
|
211
211
|
const chars = Array.from(text);
|
|
212
212
|
const slice = chars.slice(offset, offset + contentLimit).join("");
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createSessionAgentResolver, openClawSessionToOvStorageId, } from "../routing/identity-routing.js";
|
|
1
|
+
import { createSessionAgentResolver, openClawSessionToOvStorageId, resolveOpenVikingActorPeerId, sanitizeOpenVikingPeerId, } from "../routing/identity-routing.js";
|
|
2
2
|
export function createOpenVikingSessionRoutingRuntime(options) {
|
|
3
|
+
const peerRole = options.peerRole ?? "assistant";
|
|
3
4
|
const sessionAgentResolver = createSessionAgentResolver(options.peerPrefix);
|
|
4
5
|
const rememberSessionAgentId = (ctx) => {
|
|
5
6
|
sessionAgentResolver.remember(ctx);
|
|
@@ -39,11 +40,17 @@ export function createOpenVikingSessionRoutingRuntime(options) {
|
|
|
39
40
|
ovSessionId: ovSessionId || undefined,
|
|
40
41
|
};
|
|
41
42
|
rememberSessionAgentId(session);
|
|
43
|
+
const agentId = resolveAgentId(session.sessionId, session.sessionKey, session.ovSessionId);
|
|
42
44
|
return {
|
|
43
45
|
sessionId: session.sessionId,
|
|
44
46
|
sessionKey: session.sessionKey,
|
|
45
47
|
ovSessionId: session.ovSessionId,
|
|
46
|
-
agentId
|
|
48
|
+
agentId,
|
|
49
|
+
actorPeerId: resolveOpenVikingActorPeerId({
|
|
50
|
+
peerRole,
|
|
51
|
+
personPeerId: sanitizeOpenVikingPeerId(ctx?.requesterSenderId ?? ctx?.senderId),
|
|
52
|
+
assistantPeerId: agentId,
|
|
53
|
+
}),
|
|
47
54
|
};
|
|
48
55
|
};
|
|
49
56
|
const toQueryConfigContext = (session) => ({
|
|
@@ -83,7 +83,7 @@ export function registerOpenVikingToolResultTools({ registerTool, getClient, res
|
|
|
83
83
|
}
|
|
84
84
|
try {
|
|
85
85
|
const client = await getClient();
|
|
86
|
-
const result = await client.readToolResult(session.ovSessionId, parsed.toolResultId, { offset, limit, includeMetadata: true }
|
|
86
|
+
const result = await client.readToolResult(session.ovSessionId, parsed.toolResultId, { offset, limit, includeMetadata: true });
|
|
87
87
|
const returnedChars = result.content.length;
|
|
88
88
|
const nextOffset = result.offset + returnedChars;
|
|
89
89
|
const text = result.content || "(empty tool result chunk)";
|
|
@@ -167,7 +167,7 @@ export function registerOpenVikingToolResultTools({ registerTool, getClient, res
|
|
|
167
167
|
const contextChars = Math.max(0, getOptionalInteger(params.context_chars ?? params.contextChars, 300));
|
|
168
168
|
try {
|
|
169
169
|
const client = await getClient();
|
|
170
|
-
const result = await client.searchToolResult(session.ovSessionId, parsed.toolResultId, query, { limit, contextChars }
|
|
170
|
+
const result = await client.searchToolResult(session.ovSessionId, parsed.toolResultId, query, { limit, contextChars });
|
|
171
171
|
const matches = result.matches ?? [];
|
|
172
172
|
const text = matches.length
|
|
173
173
|
? [
|
|
@@ -227,7 +227,7 @@ export function registerOpenVikingToolResultTools({ registerTool, getClient, res
|
|
|
227
227
|
const limit = getPositiveInteger(params.limit, 50);
|
|
228
228
|
try {
|
|
229
229
|
const client = await getClient();
|
|
230
|
-
const result = await client.listToolResults(session.ovSessionId, { toolName, limit }
|
|
230
|
+
const result = await client.listToolResults(session.ovSessionId, { toolName, limit });
|
|
231
231
|
const items = result.tool_results ?? [];
|
|
232
232
|
const text = items.length
|
|
233
233
|
? [
|
package/dist/query-config.js
CHANGED
|
@@ -171,7 +171,13 @@ export class RuntimeQueryConfigStore {
|
|
|
171
171
|
const { params, warnings } = normalizeRuntimeQueryParams(patch);
|
|
172
172
|
const key = this.keyForScope(scope, ctx);
|
|
173
173
|
const bucket = scope === "claw" ? this.data.claws : this.data.sessions;
|
|
174
|
-
bucket[key]
|
|
174
|
+
const previous = bucket[key];
|
|
175
|
+
bucket[key] = {
|
|
176
|
+
params: { ...(previous?.params ?? {}), ...params },
|
|
177
|
+
updatedAt: Date.now(),
|
|
178
|
+
updatedBy: "command",
|
|
179
|
+
peerId: ctx.peerId,
|
|
180
|
+
};
|
|
175
181
|
this.data.updatedAt = Date.now();
|
|
176
182
|
await this.persist();
|
|
177
183
|
return { warnings };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export function resolveOpenVikingRequestHeaders(options = {}) {
|
|
2
|
+
return cleanOpenVikingRequestHeaders(options.headers);
|
|
3
|
+
}
|
|
4
|
+
export function cleanOpenVikingRequestHeaders(headers) {
|
|
5
|
+
if (headers === undefined || headers === null) {
|
|
6
|
+
return {};
|
|
7
|
+
}
|
|
8
|
+
if (typeof headers !== "object" || Array.isArray(headers)) {
|
|
9
|
+
throw new Error("openviking request headers must be an object");
|
|
10
|
+
}
|
|
11
|
+
const out = {};
|
|
12
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
13
|
+
if (typeof value !== "string") {
|
|
14
|
+
throw new Error(`openviking request header ${key} must be a string`);
|
|
15
|
+
}
|
|
16
|
+
out[key] = value;
|
|
17
|
+
}
|
|
18
|
+
return out;
|
|
19
|
+
}
|